Bard College
Bard Digital Commons
Senior Projects Spring 2011 Bard Undergraduate Senior Projects
2011
MUSCLE: A Simulation Toolkit Modeling Low
Energy Muon Beam Transport in Crystals
Nazmus Saquib
Bard College
is Open Access is brought to you for free and open access by the Bard
Undergraduate Senior Projects at Bard Digital Commons. It has been
accepted for inclusion in Senior Projects Spring 2011 by an authorized
administrator of Bard Digital Commons. For more information, please
contact digitalcommons@bard.edu.
Recommended Citation
Saquib, Nazmus, "MUSCLE: A Simulation Toolkit Modeling Low Energy Muon Beam Transport in Crystals" (2011). Senior Projects
Spring 2011. Paper 11.
hp://digitalcommons.bard.edu/senproj_s2011/11
MUSCLE: A Simulation Toolkit Modeling Low Energy Muon Beam Transport in Crystals
A Senior Project submitted to
The Division of Science, Math, and Computing
of Bard College
by
Nazmus Saquib
Annandale-on-Hudson, New York
May 2011
µ
µ
µ
µ
µ
µ
µ
+
µ
µs
µ
+
e
+
+ ν
µ
+ ν
e
µ
e
+ ν
µ
+ ν
e
ν
e
ν
µ
ν
e
ν
µ
µ
+
µ
+
µ
+
µ
+
e
µ
+
µ
+
µ
+
µ
implanted
µ
+
µ
µ
+
µ
µ
~
H
L
µ
µ µ
+
e
+
e
+
µ µ
µ
+
µ
+
µ
+
µ
+
µ
+
µ
+
µ
+
µ
+
µ
+
µ
+
ψ
c
ψ
c
µ
µ
ϑ v
2
φ p
E
0
E
0
=
1
2
M
1
v
2
0
=
1
2
M
1
v
2
1
+
1
2
M
2
v
2
2
.
Longitudinal : M
1
v
0
= M
1
v
1
cosϑ + M
2
v
2
cosφ,
Lateral : 0 = M
1
v
1
sin ϑ + M
1
v
1
sin ϑ.
V (r) r
V (r) r
v
c
v
c
M
1
v
0
= (M
1
+ M
2
)v
c
.
M
c
1
M
c
=
1
M
1
+
1
M
2
,
M
c
=
M
1
M
2
M
1
+ M
2
.
v
c
v
c
=
v
0
M
c
M
2
.
v
c
v
projectile
= v
0
v
c
=
v
0
M
c
M
1
,
v
target
= v
c
=
v
0
M
c
M
2
.
v
2
~v
c
~v
c
Φ = 2φ.
v
2
v
2
2
= v
2
c
+ v
2
c
v
2
c
cos (π Φ) = 2v
2
c
(1 cos Θ).
v
c
=
v
0
M
c
/M
2
Φ = 2φ
v
2
= 2v
0
M
c
M
2
cos φ,
v
2
T =
1
2
M
2
v
2
2
=
1
2
M
2
2v
0
M
c
cos φ
M
2
2
=
2
M
2
(v
0
M
c
cos φ)
2
T =
2
M
2
v
0
M
c
sin
Θ
2
2
=
4E
c
M
c
M
2
sin
2
Θ
2
=
4E
0
M
1
M
2
(M
1
+ M
2
)
2
sin
2
Θ
2
.
v
0
tan ϑ =
(v
0
v
c
) sin Θ
v
c
+ (v
0
v
c
) cos Θ
.
(v
0
v
c
)/v
c
= M
2
/M
1
.
tan ϑ =
(M
2
/M
1
) sin Θ
1 + (M
2
/M
1
) cos Θ
,
tan ϑ =
M
2
sin Θ
M
1
+ M
2
cos Θ
.
V (r) M
c
v
c
V (r)
Θ r
˙r = dr/dt
˙
Θ = dΘ/dt
E
c
=
1
2
M
c
v
2
0
,
E
c
=
1
2
M
c
( ˙r
2
+ r
2
˙
Θ
2
) + V (r).
J
c
= M
c
r
2
˙
Θ
J
c
J
c
= M
c
v
0
p,
p
r
2
r
2
=
v
0
p
˙
Θ
.
˙r
˙r
2
=
2 (E
c
V (r))
M
c
v
0
p
˙
Θ.
M
c
=
2 E
c
/v
2
0
˙
Θ = v
0
p/r
2
˙r
2
= v
2
0
V (r)
E
c
v
2
0
p
2
r
2
.
˙r =
dr
dt
= v
0
1
V (r)
E
c
p
r
2
1/2
.
˙r
˙
Θ dΘ/dr
dΘ
dr
=
dΘ
dt
dt
dr
=
p
r
2
1
V (r)
E
c
p
2
r
2
1/2
.
Θ = π
ˆ
−∞
p dr
r
2
1
V (r)
E
c
p
2
r
2
1/2
.
Θ π
r
min
Θ = π 2
ˆ
r
min
p dr
r
2
1
V (r)
E
c
p
2
r
2
1/2
.
1/r
φ
r
φ =
V (r)
Ze/r
V (r) Z e
φ
V = V
nn
+ V
en
+ V
ee
+ V
k
+ V
a
.
V
nn
V
ee
V
en
V
k
V
a
V
φ
I
=
V (r)
(Z
1
Z
2
e
2
/r)
.
reduced
radius R
R =
r
a
U
,
a
U
a
U
=
.8854 a
0
(Z
.23
1
+ Z
.23
2
)
φ
V (R) =
Z
1
Z
2
e
2
a R
φ
I
(R).
φ
U
= .1818e
3.2x
+ .5099e
.9423x
+ .2802e
.4028x
+ .02817e
.2016x
x
M
1
E M
2
θ
p
r
0
ρ
1
ρ
2
δ
1
δ
2
θ
cos
θ
2
=
ρ + p + δ
ρ + r
0
.
ρ ρ
1
ρ
2
δ = δ
1
+ δ
1
r
0
dr/dt r r
0
1
V (r
0
)
E
c
p
r
0
2
= 0,
E
c
V (r)
f(r)
f(r) = 1
V (r)
E
c
p
r
2
= 0.
f
0
(r) =
V
0
(r)
E
c
+ 2
p
2
r
3
f
0
(r)
f
0
(r) =
f(r) f(r
0
)
r r
0
.
f(r
0
)
f
0
(r) =
f(r)
r r
0
.
r
0
r
0
= r
f(r)
f
0
(r)
,
r
ρ
f
c
ρ = ρ
1
+ ρ
2
= (M
1
v
2
1
+ M
2
v
2
2
)/f
c
2(E
c
V (r
0
)) E
c
ρ = 2
(E
c
V (r
0
))
V
0
(r
0
)
V
0
(r
0
) ε
E
c
Z
1
Z
2
e
2
/a
ε =
a E
c
Z
1
Z
2
e
2
,
Z
1
Z
2
a
δ
a
a =
0.8853 a
0
Z
0.23
1
+ Z
0.23
2
,
a
0
= 0.529
B = p/a, R
0
= r
0
/a, R
c
= ρ/a, and ∆ = δ/a.
cos
θ
2
=
B + R
c
+
R
0
+ R
c
.
∆ = A
R
0
B
1 + G
A = 2 α ε B
β
, and G = γ
(1 + A
2
)
1/2
A
1
.
α = 1 + C
1
ε
1/2
,
β =
C
2
+ ε
1/2
C
3
+ ε
1/2
,
γ =
C
4
+ ε
C
5
+ ε
,
C
1
C
5
ε B
C
1
C
5
R
0
B
ε α, β, and γ
V (R) =
Z
1
Z
2
e
2
a R
φ(R),
a R = r/a φ(R)
λ M v E
λ[nm] =
~
M v
=
2.87 × 10
2
p
M[amu]E[eV ]
.
M = 0.114
λ = 0.287 nm E = 0.0877 eV
Lindhard Scharff
eV
1
S
LS
(E) = 8π
2a
B
~
Z
7/6
1
Z
2
(Z
2/3
1
+ Z
2/3
2
)
3/2
r
E
1
M
1
,
= K
E = 1.21
Z
7/6
1
Z
2
(Z
2/3
1
+ Z
2/3
2
)
3/2
r
E
1
M
1
.
E eV/amu E =
E
1
M
1
Z
1
Z
2
M
1
Zeigler
S
low
= a
1
E
1
M
1
a
2
+ a
3
E
1
M
1
a
4
,
E
1
M
1
< 25 keV/amu
S
high
= a
5
ln
a
7
M
1
E
1
+ a
8
E
1
M
1
M
1
E
1
a
6
E
1
M
1
25 keV/amu.
a
1
a
8
S
e
(E)
1
S
e
(E)
=
1
S
low
+
1
S
high
.
E
1
M
1
< 25 keV/amu
S
e
(E) v
0.75
1
.
M
c
a
E
c
S
e
(E) E
T
ns
= 4M
1
M
2
(M
1
+ M
2
)
2
E sin
2
(θ/2).
E
ψ = arctan
sin θ
cos θ +
M
1
M
2
!
φ = 2 π R
n
,
R
n
cos α
i
= cos α
i1
cos ψ
i
+ sin α
i1
sin ψ
i
cos α
i
.
N
1
N
L
πp
2
max
L = N
1
,
p
max
T
min
Z
1
, Z
2,
M
1
, M
2
a
T
min
p = R
n
p
max
,
R
n
S
e
eV
1
T
es
= L S
e
(E)
E
i+1
= E
i
T
ns
T
es
T
i
~
λ
D
i1
~
D
i1
~
T
i
~
4x
T
i1
~
D
i
~
λ
0
~
D
i
θ
λ
0
D
i
D
i1
π θ
π θ
φ = (π θ)/2
~
λ D
i
T
i
φ
Di-1
D
i
P
Λ
T
i-1
T
i
~
λ
0
T
i
T
i
Di-1
D
i
S
P
Λ
Dx
Θ
Φ
Φ
Φ
θ
T
i
Di-1
D
i
S
P
Λ
Dx
Ψ
θ ψ
~
D
i
T
i
Di-1
D
i
S
P
Λ
Dx
Ψ
P
ˆ
λ
0
ˆ
P ψ
~
D
i
ˆ
λ
~
T
i
|
~
P |
2
= (
~
4x ×
~
λ)
2
.
~
P
~
P = (
~
4x ×
~
λ) ×
~
λ.
s =
|
~
P |
tan φ
ψ θ
~
D
i
=
~
D
i1
+
~
4x +
~
P s
~
λ.
ˆ
λ
0
ˆ
P
ˆ
λ
ˆ
λ
0
=
ˆ
λ cos ψ +
ˆ
P sin ψ.
p
i
< p
max
, i = 1, 2, ..., 14
p
i
i th p
max
p < p
max
k p
k
k r
k
k
V
k
= π p
2
k
r
k
.
P (k)
1
V
k
, k = 1, 2, ..., 14
π
P (k) =
1
p
2
k
r
k
P (k)
p < p
max
dt
O(n
2
)
M
i
d
2
~r
i
(t)
dt
2
=
N
X
j=1
~
F
ij
=
~
F
i
(~r
i
(t)) ,
M
i
~
F
ij
=
~
F
ji
, j 6= i,
~
F
ii
= 0.
V (r)
M
i
d
2
~r
i
(t)
dt
2
=
~
F
i
(~r
i
) =
X
j6=i
V
ij
(~r
ij
) ,
r
ij
r
ij
= (|~r
i
|
2
|~r
j
|
2
)
1/2
.
4t
4t = 0.05 d
p
M/2T
m
,
T
m
V (~r) = A
BM
e
|~r|
a
BM
A
BM
a
BM
A
BM
a
BM
V (r) = D e
2α
0
(rr
0
)
2D e
α
0
(rr
0
)
.
r
0
E =
X
i
F
i
(%
h,i
) +
1
2
X
i,j (i6=j)
φ
ij
(r
ij
),
F
i
(%
h
)
% φ
ij
(r
ij
)
r
ij
F (%) φ
ij
i r
m
V (~r) = A
BM
e
|~r|
a
BM
A
BM
a
BM
V (~r) = A
BM
e
|~r|
a
BM
A
BM
52.0 (Z
1
Z
2
)
3/4
a
BM
Z
1
~
|r|
Z
2
0.5
1.0
1.5
2.0
2.5
3.0
rHÞL
500
1000
1500
VHrLHeVL
Z
2
0.5
1.0
1.5
2.0
2.5
3.0
rHÞL
2
4
6
8
10
12
VHrLHeVL
L
n
b
L/n
b
F
Cy =
V (y2) V (y1)
y2 y1
F
Cz =
V (z2) V (z1)
z2 z1
F
Cx =
V (x2) V (x1)
x2 x1
~
F
C
= {F
Cx
, F
Cy
, F
Cz
}
~
F = −∇V = (
V
x
,
V
y
,
V
z
).
~
F = −∇V =
V
r
'
V
11
V
12
|r
11
r
12
|
,
V
11
~r
11
V
12
~r
12
n 1
r
V
r
n
~
F
C
=
n
X
k=1
V
k
(r
k
)
r
k
'
n
X
k=1
V
k1
V
k2
|r
k1
r
k2
|
.
~
F
C
'
V
11
V
12
|r
11
r
12
|
+
V
21
V
22
|r
21
r
22
|
+ ... +
V
n1
V
n2
|r
n1
r
n2
|
.
4r
~
F
C
'
V
11
V
12
4r
+
V
21
V
22
4r
+ ... +
V
n1
V
n2
4r|
.
~
F
C
'
V
11
+ V
21
+ ... + V
n1
4r
V
12
+ V
22
+ ... + V
n2
4r
.
n
O(n
2
)
neighborAtomsList CoordList
V list V
forceList
currpt = CoordList[i]
currNeighbor = neighborAtomsList[j]
dist = F indDistanceBetween(currpt, currNeighbor)
V [j] = A
BM
e
dist/a
BM
sumV
V list[i] = sumV
CoordList[i][1] CoordList[i][1]
fx
V list[i+1]V list[i1]
2Step V olume
fx
V list[i]V list[i1]
Step V olume
CoordList[i][2] CoordList[i][2]
fy
V list[i+1]V list[i1]
2Step V olume
fy
V list[i]V list[i1]
Step V olume
CoordList[i][3] CoordList[i][3]
fz
V list[i+1]V list[i1]
2Step V olume
fz
V list[i]V list[i1]
Step V olume
forceList[i] fx, f y, fz
forceList
~
F
C
V
r
~
F
k
C
=
n
X
i=1
α
k
i
V (r
ic
)
r
ic
,
α
k
i
~r
ic
~
F
k
C
α
k
i
~r
ic
~r
ic
V (r
ic
)
r
ic
neighborAtomsList CoordList
V list V
forceList
fx = 0.0 fy = 0.0 fz = 0.0
~
CP CoordList[i]
~
CN neighborAtomsList[j]
dist FindDistanceBetween(
~
CP ,
~
CN)
dV dr
A
BM
a
BM
e
dist/a
BM
~
from
~
CP
~
CN
~
with {1, 0, 0}
cs
~
from·
~
with
|
~
from|∗|
~
with|
fx fx dV dr cs
~
with {0, 1, 0}
cs
~
from·
~
with
|
~
from|∗|
~
with|
fy fy dV dr cs
~
with {0, 0, 1}
cs
~
from·
~
with
|
~
from|∗|
~
with|
fz f z dV dr cs
forceList[i] fx, f y, fz
forceList
S
e
S
e
S
e
eV
1 1
4v = 4t
S
e
M
m
,
M
m
4t
4t
n
B
~
C
k
~a
~n
V =
P
8
k=1
V (~n
~
C
k
)
8
,
V (~r) ~r = ~n
~
C
k
σ1 =
s
P
8
k=1
(V (
~
C
k
) V )
2
8
.
V (~a) V
σ2 =
s
P
8
k=1
(V (
~
C
k
) V (~a))
2
8
.
= σ1 σ2 n
B
n
B
~
C
k
n
B
n
B
=
L
|
~
C
1
~
C
2
|
,
L n
B
n
B
n
B
n
B
= 5
n
B
' 45
M
m
d
2
u
dt
2
= ku R
du
dt
.
ku
(4M
m
k)
1/2
i
i + 1 i 1 (i + 1)th (i 1)th
F
b
k
=
V ( ~r
b
k
) V (~r
(b±1)
k
)
| ~r
b
k
~r
(b±1)
k
|
,
~r
b
k
k th
~r
(b±1)
k
k th
~r
b
k
~r
(b±1)
k
~r
b
k
~r
b
k
~r
(b±1)
k
~r
b
k
~r(t) = ~r
0
+ ~v
0
t +
1
2
~at
2
,
~v(t) = ~v
0
+ ~at ,
~v
i
E
i
0
30
v
i
E
i
v
i
=
r
2E
i
M
m
,
M
m
y z
~r
i
B
i
B
i
= Random(1, Y
B
Z
B
),
Y
B
Z
B
~r
i
B
i
~r(t)
t + 4t ~r(t + 4t)
t
d~r(t)/dt
4t
d~r(t + 4t/2)
dt
=
d~r(t 4t/2)
dt
+ 4t
~
F
i
(t)
M
m
,
~r(t + 4t) = ~r(t) + 4t
d~r(t + 4t/2)
dt
.
F
i
(t)
4t/2
S
e
(E)
t
E
mean
(t) =
M
m
2
3
X
k=1
[~v
k
(t)]
2
~v
k
(t) ~r
t + 4t t 4t
E
mean
(t) =
M
m
2
3
X
k=1
r
k
(t + 4t) r
k
(t 4t)
2 4t
2
.
S
e
4v
d~r(t+4t/2)
dt
= ~v
4t/2
~v
4t/2
~v
unit
~r(t + 4t) = ~r(t) + 4t (| ~v
4t/2
| 4v) ~v
unit
~r(t + 4t) ~r
rcell
k
= r
k
mod L
rcell
k
L L
dt = 0.05 L
c
r
M
m
2E
i
,
M
m
E
i
dt >
L
c
n
B
r
M
m
2E
i
n
B
n
B
n
B
n
B
= 25
dt
[100]
[110]
[111]
[110] [101] [1
¯
10] [10
¯
1]
[110] [100]
[110]
[111]
[100]
[110] [111]
[100] [110]
[110]
[100] [111]
[111]
[100] [111]
1.0 × 10
8
[100]
[111]
et. al. µ
MUSCLE: Molecular Dynamics Method #3 (Brute Force Method)
Mathematica Code
data =
ReadList@"C:\\Users\\Saquib\\Documents\\sp\\Senior_project_2nd\\scoef1.dat",
Number, RecordLists -> TrueD;
getAtomProperties@z_D:= Module@
8property = 8<<,
property = data@@zDD;
Return@propertyD
D
getAtomProperties@6D
86, 12, 12., 12.011, 2.2662, 11.364, 1., 1.03<
H*Proton Stopping Coefficients*L
getPCoef@z_D:= Module@
8pcoef = 8<<,
For@i = 2, i <= Length@data@@z + 92DDD, i++,
pcoef = AppendTo@pcoef, data@@z + 92DD@@iDDD
D;
Return@pcoefD
D
getPCoef@8D
80.75253, 0.0050314, 4.0824, 0.30067, 2455.8, 1.0181, 5069.7, 0.017426<
80
H*Calculate electronic stopping*L
getSe@z_, eekev_D:= Module@
8pcoef = 8<, se = 8<, m1 = 0.114, e0 = 0.0, e = 0.0, PEO = 25.0, pe = 0.0,
sl = 0.0, sh = 0.0, sed = 0.0, velpwr = 0.45, atrho = 0.0, dummy = 8<<,
pcoef = getPCoef@zD;
dummy = getAtomProperties@zD;
atrho = dummy@@6DD* 10^22;
H*Print@pcoefD;*L
e = eekev m1; H* per atm. mass unit? *L
pe = Max@PEO, eD;
sl = pcoef@@1DD* Hpe^Hpcoef@@2DDLL+ pcoef@@3DD* Hpe^pcoef@@4DDL;
sh = Hpcoef@@5DDHpe^pcoef@@6DDLL* Log@Hpcoef@@7DDpeL+ pcoef@@8DD* peD;
H*sh=pcoef@@5DD*Log@Hpcoef@@7DDpeL+pcoef@@8DD*peD*Hpe^pcoef@@6DDL;*L
sed = HHsl * shLHsl + shLL;
If@e > PEO,
Return@sed * atrho * 10^-23D
,
If@z £ 6, velpwr = 0.25, velpwr = 0.45D;
H*Print@sed," ",HePEOL^velpwrD;*L
sed = sed * HHe PEOL^velpwrL;
Return@sed * atrho * 10^-23D
D
D
t = getSe@26, 1D
10.7606
81
getEStopList@z_, eekev_D:= Module@
8pcoef = 8<, se = 8<, m1 = 0.114, e0 = 0.0, e = 0.0, PEO = 25.0, pe = 0.0,
sl = 0.0, sh = 0.0, sed = 0.0, velpwr = 0.45, atrho = 0.0, dummy = 8<<,
pcoef = getPCoef@zD;
dummy = getAtomProperties@zD;
atrho = dummy@@6DD* 10^22;
If@eekev < 10^-10,
For@i = 1, i £ 1000, i++,
se = AppendTo@se, 0D
D;
Return@seD
D;
e0 = 0.001 * eekev m1;
For@i = 1, i £ 1000, i++,
e = e0 * i;
pe = Max@PEO, eD;
sl = pcoef@@1DD* Hpe^pcoef@@2DDL+ pcoef@@3DD* Hpe^ pcoef@@4DDL;
sh = Hpcoef@@5DDHpe^pcoef@@6DDLL* Log@Hpcoef@@7DDpeL+ pcoef@@8DD* peD;
sed = HHsl * shLHsl + shLL;
If@e > PEO,
se = AppendTo@se, sed * atrho * 10^-23D
,
If@z £ 6, velpwr = 0.25, velpwr = 0.45D;
sed = sed * HHe PEOL^velpwrL;
se = AppendTo@se, sed * atrho * 10^-23D
D
D;
Return@seD
D
es = getEStopList@26, 0.5D;
es@@1000DD
7.87725
82
H*Generate a list of electronic stopping list*L
getEStopping@z_, e_, e0kev_, estopList_D:= Module@
8ie = 0, see = 0.0<,
ie = Round@He e0kevLD;
If@ie > 1000,
H*Print@">1000th element doesn't exist, using the 1000th value for -> e = ",
e," eV, e0kev = ",e0kevD;*L
H*Print@">1000th element doesn't exist, using the getSe@D
function for -> e = ",e," eV, e0kev = ",e0kevD;*L
Return@getSe@z, e 1000DD
D;
see = estopList@@ieDD;
If@e < e0kev,
see = estopList@@1DD* Sqrt@e e0kevD
D;
Return@seeD
D
getEStopping@26, 500, 0.5, esD
7.87725
H*Lindhard Scharff stopping*L
LSStopping@z1_, z2_, eev_D:= ModuleB
8m1 = 0.114, e0 = 0.0, se = 0.0, dummy = 8<, atrho = 0.0<,
dummy = getAtomProperties@z2D;
atrho = dummy@@6DD* 10^22;
e0 = eev m1;
se = 1.21 *
z1
76
* z2
Iz1
23
+ z2
23
M
32
*
eev
m1
;
se = se * atrho * H10^-23L;
Return@se 10DH* 10 to make it evang from evnm -
see Ion solid interaction HNastasy, MayerLpg 110 sample calculations*L
F
LSStopping@1, 26, 1000D
8.1769
83
H*basic constants*L
kg = 1.0;
sec = 1.0;
m = 1.0;
ang = 10^-10 * m;
J = Hkg * m^2Lsec^2;
eV = H1.6 * 10^H-19LL* J
MeV = eV * 10^6
c = H3.0 * 10^8Lm * sec^-2
1.6 ´ 10
-19
1.6 ´ 10
-13
3. ´ 10
8
H*preliminaries*L
muonMass = 105.65836668 * MeV c^2
atomMass = 0.055847 I6.02 * 10
23
M* kg
latticeConstant = 2.87 * ang
totalVolume = latticeConstant * latticeConstant * latticeConstant
Zmuon = 1
ZFe = 26
ZC = 6
ToeV@e_D:= e H1.6 * 10^-19L
FromeV@e_D:= e * H1.6 * 10^-19L
84
H*neighbor atoms in the unit cube*L
lx = 8latticeConstant 2, 0, 0<
ly = 80, latticeConstant 2, 0<
lz = 80, 0, latticeConstant 2<
neighborIonsBCC = List@D;
neighborIonsBCC = AppendTo@neighborIonsBCC, 80, 0, 0<D;
neighborIonsBCC = AppendTo@neighborIonsBCC, 2 * lxD;
neighborIonsBCC = AppendTo@neighborIonsBCC, 2 * lyD;
neighborIonsBCC = AppendTo@neighborIonsBCC, 2 * lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, lx + ly + lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, 2 * ly + 2 * lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, 2 * lx + 2 * lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, 2 * lx + 2 * lyD;
neighborIonsBCC = AppendTo@neighborIonsBCC, 2 * lx + 2 * ly + 2 * lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, -ly + lx + lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, 3 * ly + lx + lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, lx + ly - lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, lx + ly + 3 * lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, -lx + ly + lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, 3 * lx + ly + lzD;
topLeft = 2 * lz
topright = 2 * ly + 2 * lz
bottomLeft = 80, 0, 0<;
bottomRight = 2 * ly;
topLeft@@2DD
H*MD*L
Clear@distribution, d, dList, allDList, oldd, dbox,
vv, oldvv, vvdir, trackHistory, selist, vmaglist, ke, FD;
AbsoluteTimingB
numMuons = 50;
TotalDepth = 600 * ang;
en = 500 * eV; H*energy in ev*L
vthold = 2 * 5 * eV muonMass
ethold = 5 * eV;
dt = 0.1 * latticeConstant * muonMass H2 * enL* sec; H*time step*L
Print@en, " ", ethold, " ", dtD;
delv = 0.0;
ls = 0.0;
se = 0.0;
currE = 0.0;
vmag = 0.0;
currEev = 0.0;
numTransmission = 0;
;
85
numBackscatter = 0;
reducedv = 8<;
vvdir = 8<;
trackHistory = 8<;
selist = 8<;
vmaglist = 8<;
ke = 80.0, 0.0, 0.0<;
distribution = List@D;
depthList = 8<;
d = 8<;
dList = List@D;
allDList = List@D;
oldd = List@D;
dbox = List@D;
vv = 8<;
oldvv = List@D;
F = 8<;
H*File Operation*L
f =
OpenWrite@"C:\\Users\\Saquib\\Documents\\sp\\Senior_project_2nd\\raw_data.txt",
FormatType ® OutputForm D;
H*Potential properties*L
H*Born-Mayer parameters*L
Abm = 52.0 * HZmuon * ZFeL
34
* eV;
abm = 0.219 * ang;
MonitorB
ForBnh = 1, nh £ numMuons, nh = nh + 1,
numScatter = 0;
transmitted = False;
Clear@dList, selist, vmaglist, meanvSq, FD;
dList = List@D;
selist = 8<;
vmaglist = 8<;
meanvSq = 80.0, 0.0, 0.0<;
H*generate random v*L
currE = en;
diry = RandomReal@80.0, 0.5<D;
dirz = RandomReal@80.0, 0.5<D;
H*
diry=0.0;
;
86
dirz=0.0;
*L
vr = 2 * en muonMass ;
vy = vr * diry;
vz = vr * dirz;
vx = Hvr^2 - Hvy^2 + vz^2LL;
vv = 8vx, vy, vz<;
oldvv = 8vx, vy, vz<;
d = 80.0, RandomReal@80.0, latticeConstant<D,
RandomReal@80.0, latticeConstant<D<;
dpdt = d;
dmdt = dpdt;
dbox = d;
F = 8<;
currT = 0.0;
count = 0;
minE = en;
H*
Print@"Initializing Muon ð",n,
" velocity vector: ",vv, " vr: ",vr, " Threshold vel.: ",vtholdD;
Write@f,"Initializing Muon ð",n," velocity vector: ",
vv, " vr: ",vr, " Threshold vel.: ",vtholdD;
*L
H*loop until energy drops below threshold*L
WhileAHcurrE > etholdL&& Hd@@1DD< TotalDepthL,
If@count > 2,
For@k = 1, k £ 3, k++,
meanvSq@@kDD= HHdList@@countDD@@kDD- dList@@count - 2DD@@kDDLH2 * dtLL^2
D;
currE = HmuonMass 2L* Total@ meanvSqD;
If@minE > currE,
minE = currE
D
D;
87
H*Calculate the force acting on the muon*L
fx = 0.0;
fy = 0.0;
fz = 0.0;
H*Go through each neighbor atom and add their potential contribution*L
ForAn = 1, n £ Length@neighborIonsBCCD, n = n + 1,
currNeighbor = neighborIonsBCC@@nDD;
dist =
,
IHdbox@@1DD- currNeighbor@@1DDL
2
+
Hdbox@@2DD- currNeighbor@@2DDL
2
+ Hdbox@@3DD- currNeighbor@@3DDL
2
M;
H*Born-Mayer potential*L
dVdr = H-Abm abmL* ã
-distabm
;
from = currNeighbor - dbox;
with = lx;
H*cs=Cos@VectorAngle@from,withDD;*L
cs = HDot@from, withDLHHNorm@fromDL* HNorm@withDLL;
fx = fx + dVdr * cs;
with = ly;
H*cs=Cos@VectorAngle@from,withDD;*L
cs = HDot@from, withDLHHNorm@fromDL* HNorm@withDLL;
fy = fy + dVdr * cs;
with = lz;
H*cs=Cos@VectorAngle@from,withDD;*L
cs = HDot@from, withDLHHNorm@fromDL* HNorm@withDLL;
fz = fz + dVdr * cs;
E;
F = 8-fx, -fy, -fz<;
For@k = 1, k £ 3, k++,
H*vHt+dt2L= *L
vv@@kDD= oldvv@@kDD+ dt * F@@kDDmuonMass
D;
H*Incorporate estopping, reduce velocity*L
vvdir = Normalize@vvD;
H* Zeigler stopping *L
currEev = ToeV@currED;
88
H*seev=getEStopping@ZFe,currEev,1.0,esD;H*in eVang*L*L
seev = getSe@26, currEevD;
H*
H*LS stopping *L
currEev=ToeV@currED;
seev=LSStopping@1,26,currEevD;
*L
H*selist=AppendTo@selist,seD;*L
H*Print@seD;*L
se = seev * H1.6 * 10^H-19LLH10^-10L;
H*reduce velocity*L
delv = dt * se muonMass;
vmag = Norm@vvD;
vv = Hvmag - delvL* vvdir;
H*new d *L
For@k = 1, k £ 3, k++,
H*vHt+dt2L= *L
dpdt@@kDD= d@@kDD+ dt * vv@@kDD
D;
dList = AppendTo@dList, dpdtD;
If@dpdt@@1DD< 0,
numBackscatter = numBackscatter + 1;
H*Print@"Particle backscattered"D;*L
Break@D
D;
H*abs@lsDmight have solved the problem of getting stuck at a place*L
ls = Abs@Norm@dpdtD- Norm@dDD;
H*
Print@"e = ",currE," se = ",se," seHeVangL= ",getEStopping@ZC,ToeV@currED,
1.0,esD," ls = ",ls," del v. = ",delv," Norm@vvD= ",Norm@vvDD;
*L
H*Check Transmission*L
If@dpdt@@1DD³ TotalDepth,
transmitted = True;
numTransmission = numTransmission + 1;
Break@D;
D;
89
D;
H*find the position in the simulation cell using modulus*L
dbox@@1DD= Mod@dpdt@@1DD, latticeConstantD;
dbox@@2DD= Mod@dpdt@@2DD, latticeConstantD;
dbox@@3DD= Mod@dpdt@@3DD, latticeConstantD;
currT = currT + dt;
numScatter = numScatter + 1;
count = count + 1;
d = dpdt;
H*new v = old v - del v + force in new block,
which will be calculated in the next loop*L
oldvv = vv;
E;
H*Print@"final velocity: ",Norm@vvDD;*L
H*Print@"final depth: ",d@@1DDD;
Print@"Number of scatters: ",numScatterD;*L
H*Print@"x: ",d@@1DD," y: ",d@@2DD," z: ",d@@3DDD;*L
H*save coord. for distribution data*L
If@transmitted == True,
trackHistory = AppendTo@trackHistory, 8n, vmaglist, selist<D
D;
distribution = AppendTo@distribution, dD;
depthList = AppendTo@depthList, d@@1DDD;
allDList = AppendTo@allDList, dListD;
F
,
8"Muon ð", nh, "distance: ", d,
ProgressIndicator@Norm@dD, 80, TotalDepth<D, "Estopping: ", seev,
"Resultant Velocity: ", ProgressIndicator@Norm@vvD, 80, vr<D,
"Current Energy:", ProgressIndicator@currE, 80, en * 2<D, "Min. Energy:", minE<
F;
H*distribution*L
H*Average depth*L
Print@"Average range = ", Total@distributionDnumMuonsD;
H*Transmission and backscattering*L
Print@numTransmission, " particles transmitted, ",
numBackscatter, " particles backscattered"D;
F
90
Close@fD
F
Average range = 95.60003 ´ 10
-9
, 1.2745 ´ 10
-9
, 1.82551 ´ 10
-9
=
0 particles transmitted, 0 particles backscattered
H*Code to plot all the trajectories together*L
Manipulate@
Show@
Flatten@
Table@
Graphics3D@88ColorData@3, "ColorList"D, Line@allDList@@nDDD<,
8Red, PointSize@LargeD, Point@allDList@@nDD@@currptDDD<<,
Axes ® True, PlotRange ® Automatic,
AxesLabel ® 8x, y, z<,
PlotRangePadding ® None,
FaceGrids ® NoneD
, 8n, nMax<D
D
D,
88currpt, 1<, 1, Length@allDList@@nMaxDDD, 2<,
88zoom, Max@allDListD<, Min@allDListD, Max@allDListD, 1<,
88nMax, numMuons<, 1, numMuons, 1<
D
H*Plot depth distribution*L
Histogram@depthList, 50D
5.´ 10
-9
1.´ 10
-8
1.5´ 10
-8
2.´ 10
-8
1
2
3
4
5
6
7
91
MUSCLE: Molecular Dynamics Method #1 (Discretization method 1)
Mathematica code
ToeV@e_D:= e H1.6 * 10^-19L
FromeV@e_D:= e * H1.6 * 10^-19L
data =
ReadList@"C:\\Users\\Saquib\\Documents\\sp\\Senior_project_2nd\\scoef1.dat",
Number, RecordLists -> TrueD;
getAtomProperties@z_D:= Module@
8property = 8<<,
property = data@@zDD;
Return@propertyD
D
getAtomProperties@6D
86, 12, 12., 12.011, 2.2662, 11.364, 1., 1.03<
getPCoef@z_D:= Module@
8pcoef = 8<<,
For@i = 2, i <= Length@data@@z + 92DDD, i++,
pcoef = AppendTo@pcoef, data@@z + 92DD@@iDDD
D;
Return@pcoefD
D
getPCoef@8D
80.75253, 0.0050314, 4.0824, 0.30067, 2455.8, 1.0181, 5069.7, 0.017426<
92
getSe@z_, eekev_D:= Module@
8pcoef = 8<, se = 8<, m1 = 0.114, e0 = 0.0, e = 0.0, PEO = 25.0, pe = 0.0,
sl = 0.0, sh = 0.0, sed = 0.0, velpwr = 0.45, atrho = 0.0, dummy = 8<<,
pcoef = getPCoef@zD;
dummy = getAtomProperties@zD;
atrho = dummy@@6DD* 10^22;
H*Print@pcoefD;*L
e = eekev m1; H* per atm. mass unit? *L
pe = Max@PEO, eD;
sl = pcoef@@1DD* Hpe^Hpcoef@@2DDLL+ pcoef@@3DD* Hpe^pcoef@@4DDL;
sh = Hpcoef@@5DDHpe^pcoef@@6DDLL* Log@Hpcoef@@7DDpeL+ pcoef@@8DD* peD;
H*sh=pcoef@@5DD*Log@Hpcoef@@7DDpeL+pcoef@@8DD*peD*Hpe^pcoef@@6DDL;*L
sed = HHsl * shLHsl + shLL;
If@e > PEO,
Return@sed * atrho * 10^-23D
,
If@z £ 6, velpwr = 0.25, velpwr = 0.45D;
H*Print@sed," ",HePEOL^velpwrD;*L
sed = sed * HHe PEOL^velpwrL;
Return@sed * atrho * 10^-23D
D
D
t = getSe@6, 0.1D
5.75291
93
getEStopList@z_, eekev_D:= Module@
8pcoef = 8<, se = 8<, m1 = 0.114, e0 = 0.0, e = 0.0, PEO = 25.0, pe = 0.0,
sl = 0.0, sh = 0.0, sed = 0.0, velpwr = 0.45, atrho = 0.0, dummy = 8<<,
pcoef = getPCoef@zD;
dummy = getAtomProperties@zD;
atrho = dummy@@6DD* 10^22;
If@eekev < 10^-10,
For@i = 1, i £ 1000, i++,
se = AppendTo@se, 0D
D;
Return@seD
D;
e0 = 0.001 * eekev m1;
For@i = 1, i £ 1000, i++,
e = e0 * i;
pe = Max@PEO, eD;
sl = pcoef@@1DD* Hpe^pcoef@@2DDL+ pcoef@@3DD* Hpe^ pcoef@@4DDL;
sh = Hpcoef@@5DDHpe^pcoef@@6DDLL* Log@Hpcoef@@7DDpeL+ pcoef@@8DD* peD;
sed = HHsl * shLHsl + shLL;
If@e > PEO,
se = AppendTo@se, sed * atrho * 10^-23D
,
If@z £ 6, velpwr = 0.25, velpwr = 0.45D;
sed = sed * HHe PEOL^velpwrL;
se = AppendTo@se, sed * atrho * 10^-23D
D
D;
Return@seD
D
es = getEStopList@26, 1D;
es@@1000DD
10.7606
94
getEStopping@z_, e_, e0kev_, estopList_D:= Module@
8ie = 0, see = 0.0<,
ie = Round@He e0kevLD;
If@ie > 1000,
H*Print@">1000th element doesn't exist, using the 1000th value for -> e = ",
e," eV, e0kev = ",e0kevD;*L
H*Print@">1000th element doesn't exist, using the getSe@D
function for -> e = ",e," eV, e0kev = ",e0kevD;*L
Return@getSe@z, e 1000DD
D;
see = estopList@@ieDD;
If@e < e0kev,
see = estopList@@1DD* Sqrt@e e0kevD
D;
Return@seeD
D
getEStopping@26, 1000, 1, esD
10.7606
H*basic constants*L
kg = 1;
sec = 1;
m = 1;
ang = 10^H-10L* m;
J = Hkg * m^2Lsec^2
eV = H1.6 * 10^H-19LL* J
MeV = eV * 10^6
c = H3.0 * 10^8Lm * sec^-2
1
1.6 ´ 10
-19
1.6 ´ 10
-13
3. ´ 10
8
95
H*preliminaries*L
muonMass = 105.65836668 * MeV c^2
atomMass = 0.055847 I6.02 * 10
23
M* kg
latticeConstant = 2.87 * ang
totalVolume = latticeConstant * latticeConstant * latticeConstant
xBound = 25
yBound = 25
zBound = 25
volStep = HlatticeConstant xBoundL
numUnitCube = HlatticeConstant volStepL
3
Zmuon = 1
ZFe = 26
ZC = 6
96
H*neighbor atoms in the unit cube*L
lx = 8latticeConstant 2, 0, 0<
ly = 80, latticeConstant 2, 0<
lz = 80, 0, latticeConstant 2<
neighborIonsBCC = List@D;
neighborIonsBCC = AppendTo@neighborIonsBCC, 80, 0, 0<D;
neighborIonsBCC = AppendTo@neighborIonsBCC, 2 * lxD;
neighborIonsBCC = AppendTo@neighborIonsBCC, 2 * lyD;
neighborIonsBCC = AppendTo@neighborIonsBCC, 2 * lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, lx + ly + lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, 2 * ly + 2 * lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, 2 * lx + 2 * lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, 2 * lx + 2 * lyD;
neighborIonsBCC = AppendTo@neighborIonsBCC, 2 * lx + 2 * ly + 2 * lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, -ly + lx + lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, 3 * ly + lx + lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, lx + ly - lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, lx + ly + 3 * lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, -lx + ly + lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, 3 * lx + ly + lzD;
topLeft = 2 * lz
topright = 2 * ly + 2 * lz
bottomLeft = 80, 0, 0<;
bottomRight = 2 * ly;
topLeft@@2DD
91.435 ´ 10
-10
, 0, 0=
90, 1.435 ´ 10
-10
, 0=
90, 0, 1.435 ´ 10
-10
=
90, 0, 2.87 ´ 10
-10
=
90, 2.87 ´ 10
-10
, 2.87 ´ 10
-10
=
0
97
H*Block coordinates inside the simulation cell*L
Clear@sc, sc2D
H*sc=80,0,0<;*L
sc = List@D;
sc2 = List@D;
For@xc = 1, xc £ xBound, xc = xc + 1,
For@zc = 1, zc £ zBound, zc = zc + 1,
For@yc = 1, yc £ yBound, yc = yc + 1,
sc = AppendTo@sc, 8topLeft@@1DD+ xc * volStep,
topLeft@@2DD+ yc * volStep, bottomLeft@@3DD+ zc * volStep<D
D
D
D
For@i = 1, i £ Length@scD, i = i + 1,
sc2 = AppendTo@sc2,
8sc@@iDD@@1DD- volStep 2, sc@@iDD@@2DD- volStep 2, sc@@iDD@@3DD- volStep 2<D
D
ListPointPlot3D@sc, AxesLabel ® 8x, y, z<D
sc;
Length@sc2D
sc2;
H*,PlotRange®8-1.435,1.435<,DataRange®880,2.87<,8-1.435,1.435<<D*L
1.´ 10
-10
2.´ 10
-10
x
1.´ 10
-10
2.´ 10
-10
y
0
1.´ 10
-10
2.´ 10
-10
z
15 625
98
H*Returns the index of the block*L
detNode@num_, vstep_D:= Module@8q = 0, r = 0, eps = H10^H-5LL* ang<,
q = Quotient@num, vstepD;
H*r=Mod@num,lattConstD;*L
r = num - q * vstep;
H*Print@q," ",rD;*L
Which@
r > eps, Return@q + 1D,
r ³ 0 && q > 0, Return@qD,
r ³ 0 && q 0, Return@1D,
True, Print@"Unable to determine the cell"D; Print@q, " ", rD; Return@-1D
D
D
H*Determine the block index based on x, y, and z values of a point*L
nodeCoord@x_, y_, z_, spacing_D:= Module@8xk = 0, yk = 0, zk = 0<,
xk = detNode@x, spacingD;
yk = detNode@y, spacingD;
zk = detNode@z, spacingD;
If@Hyk + Hzk - 1L* zBound + Hxk - 1L* HxBoundL^2L> xBound * yBound * zBound,
Print@"Went Over ", xk, " ", x, " ", yk, " ", y, " ", zk, " ", zD
D;
Which@
xk > 0 && yk > 0 && zk > 0, Return@yk + Hzk - 1L* zBound + Hxk - 1L* HxBoundL^2D,
xk 0 && yk 0 && zk 0, Return@1D,
xk 0 && yk 0 && zk 1, Return@zBound + 1D,
yk 0 && zk 0 && xk 1, Return@xBound^2 + 1D
D
D
H*Potential and force field Calculations*L
H*Born-Mayer parameters*L
Abm = 52.0 * HZmuon * ZFeL
34
* eV
abm = 0.219 * ang
H*Morse parameters*L
H*For Fe*L
DeV = 0.4174 * eV
alphap = 1.3885 ang
r0 = 2.845 * ang
Clear@Vlist, V, forceList, vPlotD
Vlist = List@D;
V = List@D;
forceList = List@D;
ForAi = 1, i £ Length@sc2D, i = i + 1,
99
Clear@VD;
V = List@D;
H*Go through each neighbor atom and add their potential contribution*L
ForAn = 1, n £ Length@neighborIonsBCCD, n = n + 1,
currPt = sc2@@iDD;
currNeighbor = neighborIonsBCC@@nDD;
dist =
,
IHcurrPt@@1DD- currNeighbor@@1DDL
2
+
HcurrPt@@2DD- currNeighbor@@2DDL
2
+ HcurrPt@@3DD- currNeighbor@@3DDL
2
M;
H*Born-Mayer potential*L
V = AppendToAV, Abm * ã
-distabm
E
H*Morse Potential*L
H*V=AppendToAV,IDeV
H-2*alphap*Hdist-r0LL
-2*DeV
H-alphap*Hdist-r0LL
ME*L
E;
sumV = Total@VD;
Vlist = AppendTo@Vlist, sumVD;
E
Length@VlistD
H*Now to force field*L
For@i = 1, i £ Length@sc2D, i = i + 1,
currx = sc2@@iDD@@1DD;
curry = sc2@@iDD@@2DD;
currz = sc2@@iDD@@3DD;
H*Determine x-Boundary*L
If@sc2@@iDD@@1DD+ volStep > latticeConstant,
H*deeper-x-boundary*L
fx = HVlist@@iDD- Vlist@@nodeCoord@currx - volStep, curry, currz, volStepDDDL
HvolStepL;
,
If@sc2@@iDD@@1DD- volStep < 0,
H*nearer-x-boundary*L
fx = HVlist@@nodeCoord@currx + volStep, curry, currz, volStepDDD- Vlist@@iDDL
HvolStepL;
,
H*Not in the x-Boundary*L
fx = HVlist@@nodeCoord@currx + volStep, curry, currz, volStepDDD-
Vlist@@nodeCoord@currx - volStep, curry, currz, volStepDDDLH2 * volStepL;
D
D;
H*Determine y-Boundary*L
If@sc2@@iDD@@2DD+ volStep > latticeConstant,
100
H*right-y-boundary*L
fy = HVlist@@iDD- Vlist@@nodeCoord@currx, curry - volStep, currz, volStepDDDL
HvolStepL;
,
If@sc2@@iDD@@2DD- volStep < 0,
H*left-y-boundary*L
fy = HVlist@@nodeCoord@currx, curry + volStep, currz, volStepDDD- Vlist@@iDDL
HvolStepL;
,
H*Not in the y-Boundary*L
fy = HVlist@@nodeCoord@currx, curry + volStep, currz, volStepDDD-
Vlist@@nodeCoord@currx, curry - volStep, currz, volStepDDDLH2 * volStepL;
D
D;
H*Determine z-Boundary*L
If@sc2@@iDD@@3DD+ volStep > latticeConstant,
H*upper-z-boundary*L
fz = HVlist@@iDD- Vlist@@nodeCoord@currx, curry, currz - volStep, volStepDDDL
HvolStepL;
,
If@sc2@@iDD@@3DD- volStep < 0,
H*lower-z-boundary*L
fz = HVlist@@nodeCoord@currx, curry, currz + volStep, volStepDDD- Vlist@@iDDL
HvolStepL;
,
H*Not in the z-Boundary*L
fz = HVlist@@nodeCoord@currx, curry, currz + volStep, volStepDDD-
Vlist@@nodeCoord@currx, curry, currz - volStep, volStepDDDLH2 * volStepL;
D
D;
If@HNot@NumberQ@fxDDLÈÈHNot@NumberQ@fyDDLÈÈHNot@NumberQ@fzDDL,
Print@"Not Numeric in Node ", iDD;
forceList = AppendTo@forceList, 8fx, fy, fz<D
D
Length@VlistD
Length@forceListD
vPlot = List@D;
For@i = 1, i £ Length@forceListD, i = i + 1,
vPlot = AppendTo@vPlot, 8sc2@@iDD, forceList@@iDD<D;
D
101
H*Code to plot the force field vectors*L
Manipulate@
ListVectorPlot3D@vPlot, VectorScale ® 8Automatic, Automatic, Automatic<,
PlotRange ® 88lox, hix<, 8loy, hiy<, 8loz, hiz<<, AxesLabel ® 8x, y, z<D,
88lox, 0.0<, 0.0, latticeConstant 2, 0.2 * ang<,
88hix, 2.87 * ang<, latticeConstant 2, latticeConstant, 0.2 * ang<,
88loy, 0.0<, 0.0, latticeConstant 2, 0.2 * ang<,
88hiy, 2.87 * ang<, latticeConstant 2, latticeConstant, 0.2 * ang<,
88loz, 0.0<, 0.0, latticeConstant 2, 0.2 * ang<,
88hiz, 2.87 * ang<, latticeConstant 2, latticeConstant, 0.2 * ang<
D
H*Main molecular dynamics simulation*L
Clear@distribution, d, dList, allDList, oldd,
dbox, vv, oldvv, vvdir, trackHistory, selist, vmaglist, keD;
AbsoluteTimingB
numMuons = 1000;
TotalDepth = 1000 * ang;
en = 500 * eV; H*energy in ev*L
Print@ToeV@enDD;
vthold = 2 * 5 * eV muonMass ;
ethold = 5 * eV;
dt = 0.05 * latticeConstant * muonMass H2 * enL* sec; H*time step*L
Print@en, " ", ethold, " ", dtD;
delv = 0.0;
ls = 0.0;
se = 0.0;
currE = 0.0;
vmag = 0.0;
currEev = 0.0;
numTransmission = 0;
numBackscatter = 0;
reducedv = 8<;
vvdir = 8<;
trackHistory = 8<;
selist = 8<;
vmaglist = 8<;
ke = 80.0, 0.0, 0.0<;
distribution = List@D;
depthList = 8<;
d = 8<;
dList = List@D;
;
;
102
allDList = List@D;
oldd = List@D;
dbox = List@D;
vv = 8<;
oldvv = List@D;
H*File Operation*L
f =
OpenWrite@"C:\\Users\\Saquib\\Documents\\sp\\Senior_project_2nd\\raw_data.txt",
FormatType ® OutputForm D;
MonitorB
ForBn = 1, n £ numMuons, n = n + 1,
numScatter = 0;
transmitted = False;
Clear@dList, selist, vmaglistD;
dList = List@D;
selist = 8<;
vmaglist = 8<;
meanvSq = 80.0, 0.0, 0.0<;
H*generate random v*L
H*dirx=RandomReal@80.0,1.0<D;H*****L*L
currE = en;
diry = RandomReal@80.0, 0.5<D;
dirz = RandomReal@80.0, 0.5<D;
H*
diry=0.0;
dirz=0.0;
*L
vr = 2 * en muonMass ;
vy = vr * diry;
vz = vr * dirz;
vx = Hvr^2 - Hvy^2 + vz^2LL;
H*choose a cell to start from*L
initBoxIndex = RandomInteger@81, yBound * zBound<D;
vv = 8vx, vy, vz<;
oldvv = 8vx, vy, vz<;
d = sc2@@initBoxIndexDD;
oldd = sc2@@initBoxIndexDD;
dbox = sc2@@initBoxIndexDD;
currT = 0.0;
count = 0;
chstep = 0;
currIndex = initBoxIndex;
103
H*
Print@"Initializing Muon ð",n,
" velocity vector: ",vv, " vr: ",vr, " Threshold vel.: ",vtholdD;
Write@f,"Initializing Muon ð",n," velocity vector: ",
vv, " vr: ",vr, " Threshold vel.: ",vtholdD;
*L
H*loop until energy drops below threshold*L
While@HcurrE > etholdL&& Hd@@1DD< TotalDepthL,
For@k = 1, k £ 3, k = k + 1,
d@@kDD= oldd@@kDD+ Hvv @@kDDL* dt +
H0.5 * HforceList@@currIndexDD@@kDDL* Hdt^2LLmuonMass;
H*old v, or new v Hfollwing previous loopLsee diagram*L
vv@@kDD= oldvv@@kDD+ HforceList@@currIndexDD@@kDD* dtLmuonMass;
H*
Print@"x: ",d@@1DD," y: ",d@@2DD," z: ",d@@3DD," vr: ",Norm@vvD,
" node: ",nodeCoord@dbox@@1DD,dbox@@2DD,dbox@@3DD,volStepD,
" currIndex: ",currIndexD;
*L
If@Not@NumberQ@vv@@kDDDD,
Print@"Not Numeric in Node ", currIndex, " vv@@", k, "DD: ", vv@@kDDD
D
D;
H*Write@f,"x: ",d@@1DD," y: ",d@@2DD," z: ",
d@@3DD," vr: ",Norm@vvD," currIndex: ",currIndexD;*L
dList = AppendTo@dList, dD;
If@d@@1DD< 0,
numBackscatter = numBackscatter + 1;
H*Print@"Particle backscattered"D;*L
Break@D
D;
H*Kinetic energy*L
If@count > 2,
For@k = 1, k £ 3, k++,
104
meanvSq@@kDD= HHdList@@countDD@@kDD- dList@@count - 2DD@@kDDLH2 * dtLL^2
D;
currE = HmuonMass 2L* Total@ meanvSqD;
D;
H*currE=H12L*muonMass*HNorm@vvDL^2;*L
vvdir = Normalize@vvD;
H*abs@lsDmight have solved the problem of getting stuck at a place*L
ls = Abs@Norm@dD- Norm@olddDD;
currEev = ToeV@currED;
H*seev=getEStopping@ZFe,currEev,1.0,esD;H*in eVang*L*L
seev = getSe@26, currEevD;
selist = AppendTo@selist, seD;
H*Print@seD;*L
se = seev * H1.6 * 10^H-19LLH10^-10L;
currE = currE - se * ls;
delv = dt * se muonMass;
vmag = Norm@vvD;
vv = Hvmag - delvL* vvdir;
H*
delv=dt*semuonMass;
vvdir=Normalize@vvD;
vmag=Norm@vvD;
vv=Hvmag-delvL*vvdir;
vmaglist=AppendTo@vmaglist,vmagD;
*L
H*
Print@"e = ",currE," se = ",se," seHeVangL= ",getEStopping@ZC,ToeV@currED,
1.0,esD," ls = ",ls," del v. = ",delv," Norm@vvD= ",Norm@vvDD;
*L
H*Check Transmission*L
If@d@@1DD³ TotalDepth,
transmitted = True;
numTransmission = numTransmission + 1;
Break@D;
D;
;
105
dbox@@1DD= Mod@d@@1DD, latticeConstantD;
dbox@@2DD= Mod@d@@2DD, latticeConstantD;
dbox@@3DD= Mod@d@@3DD, latticeConstantD;
H*If@HNot@NumberQ@fxDDLÈÈHNot@NumberQ@fyDDLÈÈHNot@NumberQ@fzDDL,
Print@"Not Numeric in Node ",iDD;*L
currIndex = nodeCoord@dbox@@1DD, dbox@@2DD, dbox@@3DD, volStepD;
If@currIndex 0,
Print@"CurrIndex is 0 and dbox x, y, z: ",
dbox@@1DD, " ", dbox@@2DD, " ", dbox@@3DDD
H*currIndex=1*LD;
currT = currT + dt;
numScatter = numScatter + 1;
count = count + 1;
oldd = d;
H*new v = old v - del v + force in new block,
which will be calculated in the next loop*L
oldvv = vv;
D;
H*Print@"final velocity: ",Norm@vvDD;*L
H*Print@"final depth: ",d@@1DDD;
Print@"Number of scatters: ",numScatterD;*L
H*Print@"x: ",d@@1DD," y: ",d@@2DD," z: ",d@@3DDD;*L
H*save coord. for distribution data*L
If@transmitted == True,
trackHistory = AppendTo@trackHistory, 8n, vmaglist, selist<D
D;
distribution = AppendTo@distribution, dD;
depthList = AppendTo@depthList, d@@1DDD;
allDList = AppendTo@allDList, dListD;
F
,
8"Muon ð", n, "distance: ", d,
ProgressIndicator@Norm@dD, 80, TotalDepth<D, "Estopping: ", seev,
"Resultant Velocity: ", ProgressIndicator@Norm@vvD, 80, vr<D,
"Curent Energy:", ProgressIndicator@currE, 8ethold, en * 2<D,
"Current Block Index: ", ProgressIndicator@currIndex, 81, xBound^3<D<
F;
H*distribution*L
H*Average depth*L
;
106
Print@"Average range = ", Total@distributionDnumMuonsD;
H*Transmission and backscattering*L
Print@numTransmission, " particles transmitted, ",
numBackscatter, " particles backscattered"D;
Close@fD
F
500.
8. ´ 10
-17
8. ´ 10
-19
1.55483 ´ 10
-17
Average range = 98.60232 ´ 10
-9
, 2.73856 ´ 10
-9
, 7.53652 ´ 10
-10
=
H*Trajectory plotter code*L
Manipulate@
Show@
Flatten@
Table@
Graphics3D@88ColorData@3, "ColorList"D, Line@allDList@@nDDD<,
8Red, PointSize@LargeD, Point@allDList@@nDD@@currptDDD<<,
Axes ® True, PlotRange ® Automatic,
AxesLabel ® 8x, y, z<,
PlotRangePadding ® None,
FaceGrids ® NoneD
, 8n, nMax<D
D
D,
88currpt, 1<, 1, Length@allDList@@nMaxDDD, 2<,
88zoom, Max@allDListD<, Min@allDListD, Max@allDListD, 1<,
88nMax, numMuons<, 1, numMuons, 1<
D
107
MUSCLE: Molecular Dynamics Method #2 (Discretization Method 2)
(Electronic stopping and some other code omitted)
H*Potential and force field Calculations*L
H*Born-Mayer parameters*L
Abm = 52.0 * HZmuon * ZFeL
34
* eV
abm = 0.219 * ang
H*Morse parameters*L
H*For Fe*L
DeV = 0.4174 * eV
alphap = 1.3885 ang
r0 = 2.845 * ang
Clear@Vlist, V, forceList, vPlot, dVdrD
Vlist = List@D;
V = List@D;
forceList = List@D;
dVdr = 8<;
ForAi = 1, i £ Length@sc2D, i = i + 1,
Clear@V, dVdrD;
V = List@D;
dVdr = 8<;
fx = 0.0;
fy = 0.0;
fz = 0.0;
H*Go through each neighbor atom and add their potential contribution*L
ForAn = 1, n £ Length@neighborIonsBCCD, n = n + 1,
currPt = sc2@@iDD;
currNeighbor = neighborIonsBCC@@nDD;
H*Note: sign? which dir does the vector point to?********L
dist =
,
IHcurrPt@@1DD- currNeighbor@@1DDL
2
+
HcurrPt@@2DD- currNeighbor@@2DDL
2
+ HcurrPt@@3DD- currNeighbor@@3DDL
2
M;
H*Born-Mayer potential*L
V = AppendToAV, Abm * ã
-distabm
E;
H*dVdr=AppendToAdVdr,H-AbmabmL
-distabm
E;*L
dVdr = H-Abm abmL* ã
-distabm
;
H*If currneighbor is not equal to currpt then*LH*****L
If@currNeighbor currPt,
Print@"caught"D;
H*check where currpt actually is,
*****L
108
may be important if the particle really falls on this*****L
currPt = sc2@@i - 1DD
D;
from = currNeighbor - currPt;
with = lx;
H*cs=Cos@VectorAngle@from,withDD;*L
cs = HDot@from, withDLHHNorm@fromDL* HNorm@withDLL;
fx = fx - dVdr * cs;
with = ly;
H*cs=Cos@VectorAngle@from,withDD;*L
cs = HDot@from, withDLHHNorm@fromDL* HNorm@withDLL;
fy = fy - dVdr * cs;
with = lz;
H*cs=Cos@VectorAngle@from,withDD;*L
cs = HDot@from, withDLHHNorm@fromDL* HNorm@withDLL;
fz = fz - dVdr * cs;
If@HNot@NumberQ@fxDDLÈÈHNot@NumberQ@fyDDLÈÈHNot@NumberQ@fzDDL,
Print@"Not Numeric in Node ", iD;
Print@fx, " ", fy, " ", fzD;
Print@dVdr, " ", cs, " ", Norm@fromD, " ", Norm@withDD
D
H*Morse Potential*L
H*V=AppendToAV,IDeV
H-2*alphap*Hdist-r0LL
-2*DeV
H-alphap*Hdist-r0LL
ME*L
E;
forceList = AppendTo@forceList, 8fx, fy, fz<D;
sumV = Total@VD;
Vlist = AppendTo@Vlist, sumVD;
E
Length@VlistD
Length@forceListD
vPlot = List@D;
For@i = 1, i £ Length@forceListD, i = i + 1,
vPlot = AppendTo@vPlot, 8sc2@@iDD, forceList@@iDD<D;
D
H*Molecular dynamics method*L
Clear@distribution, d, dList, allDList, oldd,
dbox, vv, oldvv, vvdir, trackHistory, selist, vmaglist, keD;
109
dbox, vv, oldvv, vvdir, trackHistory, selist, vmaglist, keD;
AbsoluteTimingB
numMuons = 5;
TotalDepth = 1000 * ang;
en = 500 * eV; H*energy in ev*L
Print@ToeV@enDD;
vthold = 2 * 5 * eV muonMass
ethold = 5 * eV;
dt = 0.05 * latticeConstant * muonMass H2 * enL* sec; H*time step*L
Print@en, " ", ethold, " ", dtD;
delv = 0.0;
ls = 0.0;
se = 0.0;
currE = 0.0;
vmag = 0.0;
currEev = 0.0;
numTransmission = 0;
numBackscatter = 0;
reducedv = 8<;
vvdir = 8<;
trackHistory = 8<;
selist = 8<;
vmaglist = 8<;
ke = 80.0, 0.0, 0.0<;
distribution = List@D;
depthList = 8<;
d = 8<;
dList = List@D;
allDList = List@D;
oldd = List@D;
dbox = List@D;
vv = 8<;
oldvv = List@D;
H*File Operation*L
f =
OpenWrite@"C:\\Users\\Saquib\\Documents\\sp\\Senior_project_2nd\\raw_data.txt",
FormatType ® OutputForm D;
MonitorB
ForBn = 1, n £ numMuons, n = n + 1,
numScatter = 0;
transmitted = False;
;
;
110
Clear@dList, selist, vmaglistD;
dList = List@D;
selist = 8<;
vmaglist = 8<;
meanvSq = 80.0, 0.0, 0.0<;
H*generate random v*L
H*dirx=RandomReal@80.0,1.0<D;H*****L*L
currE = en;
diry = RandomReal@80.0, 0.5<D;
dirz = RandomReal@80.0, 0.5<D;
H*
diry=0.0;
dirz=0.0;
*L
vr = 2 * en muonMass ;
vy = vr * diry;
vz = vr * dirz;
vx = Hvr^2 - Hvy^2 + vz^2LL;
H*choose a cell to start from*L
initBoxIndex = RandomInteger@81, yBound * zBound<D;
vv = 8vx, vy, vz<;
oldvv = 8vx, vy, vz<;
d = sc2@@initBoxIndexDD;
oldd = sc2@@initBoxIndexDD;
dbox = sc2@@initBoxIndexDD;
currT = 0.0;
count = 0;
chstep = 0;
currIndex = initBoxIndex;
H*
Print@"Initializing Muon ð",n,
" velocity vector: ",vv, " vr: ",vr, " Threshold vel.: ",vtholdD;
Write@f,"Initializing Muon ð",n," velocity vector: ",
vv, " vr: ",vr, " Threshold vel.: ",vtholdD;
*L
H*loop until energy drops below threshold*L
While@HcurrE > etholdL&& Hd@@1DD< TotalDepthL,
For@k = 1, k £ 3, k = k + 1,
d@@kDD= oldd@@kDD+ Hvv @@kDDL* dt +
H0.5 * HforceList@@currIndexDD@@kDDL* Hdt^2LLmuonMass;
111
H*old v, or new v Hfollwing previous loopLsee diagram*L
vv@@kDD= oldvv@@kDD+ HforceList@@currIndexDD@@kDD* dtLmuonMass;
H*
Print@"x: ",d@@1DD," y: ",d@@2DD," z: ",d@@3DD," vr: ",Norm@vvD,
" node: ",nodeCoord@dbox@@1DD,dbox@@2DD,dbox@@3DD,volStepD,
" currIndex: ",currIndexD;
*L
If@Not@NumberQ@vv@@kDDDD,
Print@"Not Numeric in Node ", currIndex, " vv@@", k, "DD: ", vv@@kDDD
D
D;
H*Write@f,"x: ",d@@1DD," y: ",d@@2DD," z: ",
d@@3DD," vr: ",Norm@vvD," currIndex: ",currIndexD;*L
dList = AppendTo@dList, dD;
If@d@@1DD< 0,
numBackscatter = numBackscatter + 1;
H*Print@"Particle backscattered"D;*L
Break@D
D;
If@count > 2,
For@k = 1, k £ 3, k++,
meanvSq@@kDD= HHdList@@countDD@@kDD- dList@@count - 2DD@@kDDLH2 * dtLL^2
D;
currE = HmuonMass 2L* Total@ meanvSqD;
D;
H*currE=H12L*muonMass*HNorm@vvDL^2;*L
vvdir = Normalize@vvD;
H*abs@lsDmight have solved the problem of getting stuck at a place*L
ls = Abs@Norm@dD- Norm@olddDD;
currEev = ToeV@currED;
H*seev=getEStopping@ZFe,currEev,1.0,esD;H*in eVang*L*L
seev = getSe@26, currEevD;
selist = AppendTo@selist, seD;
112
H*Print@seD;*L
se = seev * H1.6 * 10^H-19LLH10^-10L;
currE = currE - se * ls;
delv = dt * se muonMass;
vmag = Norm@vvD;
vv = Hvmag - delvL* vvdir;
H*
Print@"e = ",currE," se = ",se," seHeVangL= ",getEStopping@ZC,ToeV@currED,
1.0,esD," ls = ",ls," del v. = ",delv," Norm@vvD= ",Norm@vvDD;
*L
H*Check Transmission*L
If@d@@1DD³ TotalDepth,
transmitted = True;
numTransmission = numTransmission + 1;
Break@D;
D;
dbox@@1DD= Mod@d@@1DD, latticeConstantD;
dbox@@2DD= Mod@d@@2DD, latticeConstantD;
dbox@@3DD= Mod@d@@3DD, latticeConstantD;
H*If@HNot@NumberQ@fxDDLÈÈHNot@NumberQ@fyDDLÈÈHNot@NumberQ@fzDDL,
Print@"Not Numeric in Node ",iDD;*L
currIndex = nodeCoord@dbox@@1DD, dbox@@2DD, dbox@@3DD, volStepD;
If@currIndex 0,
Print@"CurrIndex is 0 and dbox x, y, z: ",
dbox@@1DD, " ", dbox@@2DD, " ", dbox@@3DDD
H*currIndex=1*LD;
currT = currT + dt;
numScatter = numScatter + 1;
count = count + 1;
oldd = d;
H*new v = old v - del v + force in new block,
which will be calculated in the next loop*L
oldvv = vv;
D;
H*Print@"final velocity: ",Norm@vvDD;*L
113
H*Print@"final depth: ",d@@1DDD;
Print@"Number of scatters: ",numScatterD;*L
H*Print@"x: ",d@@1DD," y: ",d@@2DD," z: ",d@@3DDD;*L
H*save coord. for distribution data*L
If@transmitted == True,
trackHistory = AppendTo@trackHistory, 8n, vmaglist, selist<D
D;
distribution = AppendTo@distribution, dD;
depthList = AppendTo@depthList, d@@1DDD;
allDList = AppendTo@allDList, dListD;
H*Pause@2D;*L
F
,
8"Muon ð", n, "distance: ", d,
ProgressIndicator@Norm@dD, 80, TotalDepth<D, "Estopping: ", seev,
"Resultant Velocity: ", ProgressIndicator@Norm@vvD, 80, vr<D,
"Curent Energy:", ProgressIndicator@currE, 8ethold, en * 2<D,
"Current Block Index: ", ProgressIndicator@currIndex, 81, xBound^3<D<
F;
H*distribution*L
H*Average depth*L
Print@"Average range = ", Total@distributionDnumMuonsD;
H*Transmission and backscattering*L
Print@numTransmission, " particles transmitted, ",
numBackscatter, " particles backscattered"D;
Close@fD
F
114
MUSCLE: Evaluation to find a suitable number of blocks for MD Discretization methods.
Mathematica Code
ang = 10^-10;
latticeConstant = 2.87 * ang;
eV = 1.6 * 10^-19;
H*neighbor atoms in the unit cube*L
lx = 8latticeConstant 2, 0, 0<
ly = 80, latticeConstant 2, 0<
lz = 80, 0, latticeConstant 2<
neighborIonsBCC = List@D;
neighborIonsBCC = AppendTo@neighborIonsBCC, 80, 0, 0<D;
neighborIonsBCC = AppendTo@neighborIonsBCC, 2 * lxD;
neighborIonsBCC = AppendTo@neighborIonsBCC, 2 * lyD;
neighborIonsBCC = AppendTo@neighborIonsBCC, 2 * lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, lx + ly + lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, 2 * ly + 2 * lzD;
H*wrong!->neighborIonsBCC=AppendTo@neighborIonsBCC,lx-ly-lzD;*L
neighborIonsBCC = AppendTo@neighborIonsBCC, 2 * lx + 2 * lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, 2 * lx + 2 * lyD;
neighborIonsBCC = AppendTo@neighborIonsBCC, 2 * lx + 2 * ly + 2 * lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, -ly + lx + lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, 3 * ly + lx + lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, lx + ly - lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, lx + ly + 3 * lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, -lx + ly + lzD;
neighborIonsBCC = AppendTo@neighborIonsBCC, 3 * lx + ly + lzD;
91.435 ´ 10
-10
, 0, 0=
90, 1.435 ´ 10
-10
, 0=
90, 0, 1.435 ´ 10
-10
=
getNumberOfBlocksEvaluation@ABM_, aBM_, L_, neighbor_D:= ModuleA
8Vr = 0.0, dis = 0.0, done = False, numB = 1, sig1 = 0.0,
sig2 = 0.0, ep = 0.0, eps = 3.0 * 10^H-8L, edgex = 8<, edgey = 8<,
edgez = 8<, corners = 8<, origin = 8<, center = 8<, eplist = 8<<,
H*While@doneFalse,*L
ForAi = 1, i < 30, i++,
H*Initial edge length*L
edgex = 8L numB, 0.0, 0.0<;
edgey = 80.0, L numB, 0.0<;
edgez = 80.0, 0.0, L numB<;
origin = 80.0, 0.0, 0.0<;
;
115
center = Hedgex + edgey + edgezL2;
Clear@cornersD;
corners = 8<;
H*8 corners*L
corners = AppendTo@corners, originD;
corners = AppendTo@corners, edgexD;
corners = AppendTo@corners, edgeyD;
corners = AppendTo@corners, edgezD;
corners = AppendTo@corners, edgex + edgeyD;
corners = AppendTo@corners, edgex + edgezD;
corners = AppendTo@corners, edgey + edgezD;
corners = AppendTo@corners, edgex + edgey + edgezD;
Vr = 0.0;
sig1 = 0.0;
sig2 = 0.0;
ForAs = 1, s £ Length@cornersD, s = s + 1,
dis =
,
IHcorners@@sDD@@1DD- neighbor@@1DDL
2
+ Hcorners@@sDD@@2DD- neighbor@@2DDL
2
+
Hcorners@@sDD@@3DD- neighbor@@3DDL
2
M;
Vr = Vr + ABM * ã
-disaBM
;
E;
Vr = Vr 8;
ForAs = 1, s £ Length@cornersD, s = s + 1,
sig1 = sig1 + IABM * ã
-Norm@corners@@sDDDaBM
- VrM^2;
sig2 = sig2 + IABM * ã
-Norm@corners@@sDDDaBM
- ABM * ã
-Norm@centerDaBM
M^2;
E;
sig1 = sig1 8;
sig1 = Sqrt@sig1D;
sig2 = sig2 8;
sig2 = Sqrt@sig2D;
ep = sig1 - sig2;
H*If@ep>eps,
numB=numB+5
,
done=True
D;
D;
*L
eplist = AppendTo@eplist, 8numB, ep<D;
numB = numB + 5
E;
ListPlot@eplist, Joined ® True, Mesh ® All,
AxesLabel ® 8n
B
, Ε<, PlotRange ® All, AxesOrigin ® 80, Min@eplistD<D
116
H*Return@eplistD*L
E
getNumberOfBlocksEvaluationA52.0 * H26L
34
* eV,
0.219 ang, 2.87, neighborIonsBCC@@10DDangE
100
120
140
0
2.´ 10
-26
4.´ 10
-26
6.´ 10
-26
8.´ 10
-26
1.´ 10
-25
Ε
117
MUSCLE: Born-Mayer Potential plot for different elements
Mathematica Code
ShowA
FlattenA
TableA
GraphicsA
PlotAHz2L
34
* 52.0 * ã
-r0.219
, 8r, 0.0, 3.0<,
AxesLabel ® 8"rHÞL", "VHrLHeVL"<, LabelStyle ® Directive@MediumD,
ColorFunction ® Function@8z2<, 8z2 * 0.1, z2 * 0.5, z2 * 2<D,
PlotRange ® All
E
E,
8z2, 1, 92, 10<E
E
E
0.5
1.0
1.5
2.0
2.5
3.0
rHÞL
500
1000
1500
VHrLHeVL
118
MUSCLE: Binary Collision Approximation code (C++)
(Random neighbor selection code as presented in the last section of Chapter 2, loosely
based on the Fortran code for TRIM Monte Carlo simulation)
Globals.h (global functions and variables)
#include <iostream>
#include <fstream>
//#include <cstdlib>
//#include <cmath>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
#ifndef talk
#define talk 0
#endif
#ifndef PEO
//in PSTOP (i.e. calculateSE) vel. proportional stopping below velocity PEO (Pg-219,
ln 1210)
#define PEO 25.000;
#endif
void exitOnError(char* errmsg);
//numeric functions that need to be redefined
double Max(double a, double b);
double Min(double a, double b);
int Max(int a, int b);
int Min(int a, int b);
//int Abs(int a);
double Abs(double a);
//utilities
int whichBin (double e, double maxe, int numBins);
double generateRandom(int seed);
void printarray(char* arrayname, double array[], int size);
void printarray(char* arrayname, int array[], int size);
void testarray();
Globals.cpp
119
Globals.cpp
#include "Globals.h"
void exitOnError(char* errmsg)
{
cout << errmsg << endl;
exit(1);
}
double Max(double a, double b)
{
return (b<a)? a:b;
}
double Min(double a, double b)
{
return (a<b)? a:b;
}
int Max(int a, int b)
{
return (b<a)? a:b;
}
int Min(int a, int b)
{
return (a<b)? a:b;
}
double Abs(double a)
{
if(a < 0.0) return -a;
}
//function to decide which bin an epsilon value falls into
int whichBin (double e, double maxe, int numBins)
{
double interval = maxe / numBins;
for(int i = 0; i < numBins; i++)
{
double low = i*interval;
double high = (i + 1)*interval;
if((e>=low) && (e<high))
return i;
}
}
void printarray(char* arrayname, double array[], int size)
{
cout << endl << "Printing " << arrayname << endl;
for (int i = 0; i <= size; i++)
{
cout << "\t " << array[i];
}
cout << endl;
cout << "Done with printing " << arrayname << endl;
}
void printarray(char* arrayname, int array[], int size)
{
cout << endl << "Printing " << arrayname << endl;
for (int i = 0; i <= size; i++)
{
cout << "\t " << array[i];
}
cout << endl;
cout << "Done with printing " << arrayname << endl;
}
void testarray()
{
int row = 3, column = 7;
cout << endl << "Printing array.." << endl;
for (int i = 0; i <= row; i++)
{
cout << "row " << i << ": ";
for (int j = 0; j <= column; j++)
{
//activate this line with the proper array name
//cout << "\t " << mt[i][j];
}
cout << endl;
}
cout << "Done with printing array" << endl;
//int **p = zt;
//double **c = mt;
//print2darray("zt", p, 3, 7);
//print2darray("mt", c, 3, 7);
}
double generateRandom(int seed)
{
//srand(time(NULL));
//srand(seed);
srand(seed);
double e;
//random epsilon, generates between the range (0,1]
e = (double)rand()/((double)(RAND_MAX)+(double)(1));
return e;
}
120
#include "Globals.h"
void exitOnError(char* errmsg)
{
cout << errmsg << endl;
exit(1);
}
double Max(double a, double b)
{
return (b<a)? a:b;
}
double Min(double a, double b)
{
return (a<b)? a:b;
}
int Max(int a, int b)
{
return (b<a)? a:b;
}
int Min(int a, int b)
{
return (a<b)? a:b;
}
double Abs(double a)
{
if(a < 0.0) return -a;
}
//function to decide which bin an epsilon value falls into
int whichBin (double e, double maxe, int numBins)
{
double interval = maxe / numBins;
for(int i = 0; i < numBins; i++)
{
double low = i*interval;
double high = (i + 1)*interval;
if((e>=low) && (e<high))
return i;
}
}
void printarray(char* arrayname, double array[], int size)
{
cout << endl << "Printing " << arrayname << endl;
for (int i = 0; i <= size; i++)
{
cout << "\t " << array[i];
}
cout << endl;
cout << "Done with printing " << arrayname << endl;
}
void printarray(char* arrayname, int array[], int size)
{
cout << endl << "Printing " << arrayname << endl;
for (int i = 0; i <= size; i++)
{
cout << "\t " << array[i];
}
cout << endl;
cout << "Done with printing " << arrayname << endl;
}
void testarray()
{
int row = 3, column = 7;
cout << endl << "Printing array.." << endl;
for (int i = 0; i <= row; i++)
{
cout << "row " << i << ": ";
for (int j = 0; j <= column; j++)
{
//activate this line with the proper array name
//cout << "\t " << mt[i][j];
}
cout << endl;
}
cout << "Done with printing array" << endl;
//int **p = zt;
//double **c = mt;
//print2darray("zt", p, 3, 7);
//print2darray("mt", c, 3, 7);
}
double generateRandom(int seed)
{
//srand(time(NULL));
//srand(seed);
srand(seed);
double e;
//random epsilon, generates between the range (0,1]
e = (double)rand()/((double)(RAND_MAX)+(double)(1));
return e;
}
rstop.h (electronic stopping module)
#include "Globals.h"
struct rstopData
{
double se[1000];
//double sn;
double vfermi; //set this 0 when initialized. (for the time being, I dont
calculate this)
};
void getrStop(int z1, int z2, double ee, int units, double lfctr, double vfermi,
rstopData& rstopdata);
double calculaterSE(double m1, double m2, int z1, int z2, double e, double pcoef[]);
121
#include "Globals.h"
struct rstopData
{
double se[1000];
//double sn;
double vfermi; //set this 0 when initialized. (for the time being, I dont
calculate this)
};
void getrStop(int z1, int z2, double ee, int units, double lfctr, double vfermi,
rstopData& rstopdata);
double calculaterSE(double m1, double m2, int z1, int z2, double e, double pcoef[]);
rstop.cpp
#include "rstop.h"
#include "scoef.h"
//Calculate electronic stopping cross section using data from scoef1.dat
//ee - ion energy in keV
//note: we won't use the parameter lfctr and vfermi b/c they are not used in the
proton calculation.
void getrStop(int z1, int z2, double ee, int units, double lfctr, double vfermi,
rstopData& rstopdata)
{
if (z1 > 92) exitOnError("Error: atomic number is greater than 92. Exiting..");
if (ee < pow(10,-10))
{
for (int i = 1; i <= 1000; i++) rstopdata.se[i] = 0;
return;
}
scoefData ionScoef, targetScoef;
getstructScoef(z1, ionScoef, "scoef1.dat");
getstructScoef(z2, targetScoef, "scoef1.dat");
// m1 and mm1 corrections (pg-217, line 620 and 630) are not included. we can change
it from inside if need arises.
//m1 in this case is a proton
double m1 = 1.0078; //ionScoef.m1;
double e0 = 0.001 * ee/m1; //for 1000 values of stopping
if (e0 > 100000) exitOnError("(Ion Energy/atomic mass)*0.001 ratio is bigger than
100000! Exiting..");
for (int i = 1; i <= 1000; i++)
{
double e = e0 * i;
//calculate electronic stopping with atomic weight of solid (M2 column in
scoef.dat)
//be careful, m1 and m2 are not what they seem in the fortran code (pg217). Don't
confuse between targetScoef's or ionScoef's m1 and m2.
//we calculate only the proton's electron stopping here. (PSTOP)
rstopdata.se[i] = calculaterSE(m1, targetScoef.m2, z1, z2, e, targetScoef.pcoef);
//convert to ev-angstrom...I don't care about the parameter 'units' right now!
//do the following for testing. The last test value should match the stopping
table, //which is in ev-angstrom.
if (talk == 4)
{
double test = rstopdata.se[i];
test = test * targetScoef.atrho * pow(10, -23);
//print every 10th value
if ((i%10)==0)
{
//cout << "bin: " << i << ", Se = " << test << "\n";
cout << test << ",";
}
}
//trim85 takes rstop values in ev-Ang.2, so convert to that format
rstopdata.se[i] = rstopdata.se[i] * 10;
}
//check the pcoef values in targetData
if( talk == 2)
{
cout << "Test the PCoef values in targetScoef" << endl;
cout << "\t" << targetScoef.pcoef[1] << "\t" << targetScoef.pcoef[2] << "\t"
<< targetScoef.pcoef[3] << "\t" << targetScoef.pcoef[4] << "\t" <<
targetScoef.pcoef[5] << "\t" << targetScoef.pcoef[6] << "\t" << targetScoef.pcoef[7]
<< "\t" << targetScoef.pcoef[8] << "\n" << endl;
}
//we are done here..
}
//This is PSTOP subroutine in pg-219
double calculaterSE(double m1, double m2, int z1, int z2, double e, double pcoef[])
{
double se;
double peo = (double)PEO; //had to do this because compiler is not accepting PEO
as double!
double pe = Max(peo, e);
double sl = pcoef[1]*(pow(pe,pcoef[2])) + pcoef[3]*(pow(pe,pcoef[4]));
double sh = ( pcoef[5] / ( pow(pe,pcoef[6]) ) ) * log( (pcoef[7]/pe) + pcoef[8]*pe
);
se = ((sl*sh)/(sl+sh));
//PEO is defined in Globals.h
if(e > peo) return se;
else
{
double velpwr = 0.45;
if (z2 <= 6) velpwr = 0.25;
se = se * pow((e/peo),velpwr);
return se;
}
}
122
#include "rstop.h"
#include "scoef.h"
//Calculate electronic stopping cross section using data from scoef1.dat
//ee - ion energy in keV
//note: we won't use the parameter lfctr and vfermi b/c they are not used in the
proton calculation.
void getrStop(int z1, int z2, double ee, int units, double lfctr, double vfermi,
rstopData& rstopdata)
{
if (z1 > 92) exitOnError("Error: atomic number is greater than 92. Exiting..");
if (ee < pow(10,-10))
{
for (int i = 1; i <= 1000; i++) rstopdata.se[i] = 0;
return;
}
scoefData ionScoef, targetScoef;
getstructScoef(z1, ionScoef, "scoef1.dat");
getstructScoef(z2, targetScoef, "scoef1.dat");
// m1 and mm1 corrections (pg-217, line 620 and 630) are not included. we can change
it from inside if need arises.
//m1 in this case is a proton
double m1 = 1.0078; //ionScoef.m1;
double e0 = 0.001 * ee/m1; //for 1000 values of stopping
if (e0 > 100000) exitOnError("(Ion Energy/atomic mass)*0.001 ratio is bigger than
100000! Exiting..");
for (int i = 1; i <= 1000; i++)
{
double e = e0 * i;
//calculate electronic stopping with atomic weight of solid (M2 column in
scoef.dat)
//be careful, m1 and m2 are not what they seem in the fortran code (pg217). Don't
confuse between targetScoef's or ionScoef's m1 and m2.
//we calculate only the proton's electron stopping here. (PSTOP)
rstopdata.se[i] = calculaterSE(m1, targetScoef.m2, z1, z2, e, targetScoef.pcoef);
//convert to ev-angstrom...I don't care about the parameter 'units' right now!
//do the following for testing. The last test value should match the stopping
table, //which is in ev-angstrom.
if (talk == 4)
{
double test = rstopdata.se[i];
test = test * targetScoef.atrho * pow(10, -23);
//print every 10th value
if ((i%10)==0)
{
//cout << "bin: " << i << ", Se = " << test << "\n";
cout << test << ",";
}
}
//trim85 takes rstop values in ev-Ang.2, so convert to that format
rstopdata.se[i] = rstopdata.se[i] * 10;
}
//check the pcoef values in targetData
if( talk == 2)
{
cout << "Test the PCoef values in targetScoef" << endl;
cout << "\t" << targetScoef.pcoef[1] << "\t" << targetScoef.pcoef[2] << "\t"
<< targetScoef.pcoef[3] << "\t" << targetScoef.pcoef[4] << "\t" <<
targetScoef.pcoef[5] << "\t" << targetScoef.pcoef[6] << "\t" << targetScoef.pcoef[7]
<< "\t" << targetScoef.pcoef[8] << "\n" << endl;
}
//we are done here..
}
//This is PSTOP subroutine in pg-219
double calculaterSE(double m1, double m2, int z1, int z2, double e, double pcoef[])
{
double se;
double peo = (double)PEO; //had to do this because compiler is not accepting PEO
as double!
double pe = Max(peo, e);
double sl = pcoef[1]*(pow(pe,pcoef[2])) + pcoef[3]*(pow(pe,pcoef[4]));
double sh = ( pcoef[5] / ( pow(pe,pcoef[6]) ) ) * log( (pcoef[7]/pe) + pcoef[8]*pe
);
se = ((sl*sh)/(sl+sh));
//PEO is defined in Globals.h
if(e > peo) return se;
else
{
double velpwr = 0.45;
if (z2 <= 6) velpwr = 0.25;
se = se * pow((e/peo),velpwr);
return se;
}
}
123
#include "rstop.h"
#include "scoef.h"
//Calculate electronic stopping cross section using data from scoef1.dat
//ee - ion energy in keV
//note: we won't use the parameter lfctr and vfermi b/c they are not used in the
proton calculation.
void getrStop(int z1, int z2, double ee, int units, double lfctr, double vfermi,
rstopData& rstopdata)
{
if (z1 > 92) exitOnError("Error: atomic number is greater than 92. Exiting..");
if (ee < pow(10,-10))
{
for (int i = 1; i <= 1000; i++) rstopdata.se[i] = 0;
return;
}
scoefData ionScoef, targetScoef;
getstructScoef(z1, ionScoef, "scoef1.dat");
getstructScoef(z2, targetScoef, "scoef1.dat");
// m1 and mm1 corrections (pg-217, line 620 and 630) are not included. we can change
it from inside if need arises.
//m1 in this case is a proton
double m1 = 1.0078; //ionScoef.m1;
double e0 = 0.001 * ee/m1; //for 1000 values of stopping
if (e0 > 100000) exitOnError("(Ion Energy/atomic mass)*0.001 ratio is bigger than
100000! Exiting..");
for (int i = 1; i <= 1000; i++)
{
double e = e0 * i;
//calculate electronic stopping with atomic weight of solid (M2 column in
scoef.dat)
//be careful, m1 and m2 are not what they seem in the fortran code (pg217). Don't
confuse between targetScoef's or ionScoef's m1 and m2.
//we calculate only the proton's electron stopping here. (PSTOP)
rstopdata.se[i] = calculaterSE(m1, targetScoef.m2, z1, z2, e, targetScoef.pcoef);
//convert to ev-angstrom...I don't care about the parameter 'units' right now!
//do the following for testing. The last test value should match the stopping
table, //which is in ev-angstrom.
if (talk == 4)
{
double test = rstopdata.se[i];
test = test * targetScoef.atrho * pow(10, -23);
//print every 10th value
if ((i%10)==0)
{
//cout << "bin: " << i << ", Se = " << test << "\n";
cout << test << ",";
}
}
//trim85 takes rstop values in ev-Ang.2, so convert to that format
rstopdata.se[i] = rstopdata.se[i] * 10;
}
//check the pcoef values in targetData
if( talk == 2)
{
cout << "Test the PCoef values in targetScoef" << endl;
cout << "\t" << targetScoef.pcoef[1] << "\t" << targetScoef.pcoef[2] << "\t"
<< targetScoef.pcoef[3] << "\t" << targetScoef.pcoef[4] << "\t" <<
targetScoef.pcoef[5] << "\t" << targetScoef.pcoef[6] << "\t" << targetScoef.pcoef[7]
<< "\t" << targetScoef.pcoef[8] << "\n" << endl;
}
//we are done here..
}
//This is PSTOP subroutine in pg-219
double calculaterSE(double m1, double m2, int z1, int z2, double e, double pcoef[])
{
double se;
double peo = (double)PEO; //had to do this because compiler is not accepting PEO
as double!
double pe = Max(peo, e);
double sl = pcoef[1]*(pow(pe,pcoef[2])) + pcoef[3]*(pow(pe,pcoef[4]));
double sh = ( pcoef[5] / ( pow(pe,pcoef[6]) ) ) * log( (pcoef[7]/pe) + pcoef[8]*pe
);
se = ((sl*sh)/(sl+sh));
//PEO is defined in Globals.h
if(e > peo) return se;
else
{
double velpwr = 0.45;
if (z2 <= 6) velpwr = 0.25;
se = se * pow((e/peo),velpwr);
return se;
}
}
scoef.h (to read data from file)
#include "Globals.h"
struct scoefData
{
int z1;
double mm1, m1, m2, rho, atrho, vfermi;
double lfctr;
double pcoef[8];
};
//this was just a test function
void scoef(int z1, double mm1, double m1, double m2, double rho, double atrho, double
vfermi, double lfctr, double pcoef[]);
//this is the one we will be using
void getstructScoef(int zz, scoefData& scoefdata, char* filename);
scoef.cpp
#include "scoef.h"
void getstructScoef(int zz, scoefData& scoefdata, char* filename)
{
if (talk == 2) cout << "Reading scoeff data file for atmoic no. " << zz << endl;
ifstream instream;
instream.open(filename);
if (!instream)
{
exitOnError("Unable to open file ");
}
int j = 0, i = 0, z = zz;
//dummy var
double xx, zero;
//iterate to the definite row - 1
for( i = 1; i <= 92; i++)
{
instream >> j >> xx >> xx >> xx >> xx >> xx >> xx >> xx;
if (j == z-1) break;
}
//now input the desired row to our structure
instream >> scoefdata.z1 >> scoefdata.mm1 >> scoefdata.m1 >> scoefdata.m2 >>
scoefdata.rho >> scoefdata.atrho >> scoefdata.vfermi >> scoefdata.lfctr;
//cout << "Testing the input.." << endl << "Z = " << scoefdata.z1 << endl << "rho
= " << scoefdata.rho << endl;
instream.close();
//find proton stopping power coefficients in the second data set
instream.open(filename);
if (!instream)
{
exitOnError("Unable to open data file ");
}
//dummy var
int k; double s;
//skip 92 lines
for( i = 1; i <= 92; i++)
{
instream >> k >> s >> s >> s >> s >> s >> s >> s;
}
for( i = 1; i <= 92; i++)
{
instream >> j >> scoefdata.pcoef[1] >> scoefdata.pcoef[2] >>
scoefdata.pcoef[3] >> scoefdata.pcoef[4] >> scoefdata.pcoef[5] >> scoefdata.pcoef[6]
>> scoefdata.pcoef[7] >> scoefdata.pcoef[8];
//cout << j << "\t" << pcoef[0] << "\t" << pcoef[1] << "\t" << pcoef[2] <<
"\t" << pcoef[3] << "\t" << pcoef[4] << "\t" << pcoef[5] << "\t" << pcoef[6] << "\t"
<< pcoef[7] << "\n" << endl;
if (j == z) break;
}
//cout << "Testing the input on second data set (proton coefficients)" << endl <<
"Z = " << scoefdata.z1 << endl << "pcoef[1] = " << scoefdata.pcoef[1] << endl;
instream.close();
//multiply atrho by 10^22
double temprho = scoefdata.atrho;
temprho = temprho * 1.0 * pow(10, 22);
scoefdata.atrho = temprho;
if (talk == 2) cout << "Done loading data from " << filename << " for atomic no. "
<< zz << endl;
}
124
#include "scoef.h"
void getstructScoef(int zz, scoefData& scoefdata, char* filename)
{
if (talk == 2) cout << "Reading scoeff data file for atmoic no. " << zz << endl;
ifstream instream;
instream.open(filename);
if (!instream)
{
exitOnError("Unable to open file ");
}
int j = 0, i = 0, z = zz;
//dummy var
double xx, zero;
//iterate to the definite row - 1
for( i = 1; i <= 92; i++)
{
instream >> j >> xx >> xx >> xx >> xx >> xx >> xx >> xx;
if (j == z-1) break;
}
//now input the desired row to our structure
instream >> scoefdata.z1 >> scoefdata.mm1 >> scoefdata.m1 >> scoefdata.m2 >>
scoefdata.rho >> scoefdata.atrho >> scoefdata.vfermi >> scoefdata.lfctr;
//cout << "Testing the input.." << endl << "Z = " << scoefdata.z1 << endl << "rho
= " << scoefdata.rho << endl;
instream.close();
//find proton stopping power coefficients in the second data set
instream.open(filename);
if (!instream)
{
exitOnError("Unable to open data file ");
}
//dummy var
int k; double s;
//skip 92 lines
for( i = 1; i <= 92; i++)
{
instream >> k >> s >> s >> s >> s >> s >> s >> s;
}
for( i = 1; i <= 92; i++)
{
instream >> j >> scoefdata.pcoef[1] >> scoefdata.pcoef[2] >>
scoefdata.pcoef[3] >> scoefdata.pcoef[4] >> scoefdata.pcoef[5] >> scoefdata.pcoef[6]
>> scoefdata.pcoef[7] >> scoefdata.pcoef[8];
//cout << j << "\t" << pcoef[0] << "\t" << pcoef[1] << "\t" << pcoef[2] <<
"\t" << pcoef[3] << "\t" << pcoef[4] << "\t" << pcoef[5] << "\t" << pcoef[6] << "\t"
<< pcoef[7] << "\n" << endl;
if (j == z) break;
}
//cout << "Testing the input on second data set (proton coefficients)" << endl <<
"Z = " << scoefdata.z1 << endl << "pcoef[1] = " << scoefdata.pcoef[1] << endl;
instream.close();
//multiply atrho by 10^22
double temprho = scoefdata.atrho;
temprho = temprho * 1.0 * pow(10, 22);
scoefdata.atrho = temprho;
if (talk == 2) cout << "Done loading data from " << filename << " for atomic no. "
<< zz << endl;
}
monte.h (BCA Monte Carlo Simulation)
125
monte.h (BCA Monte Carlo Simulation)
#include "Globals.h"
//functions
void Initialize();
void calculateAvgMassOfLayer();
void getStoppingForTarget();
void setInitialConditions();
void MonteCarlo();
void printFinalDetails();
void writeToFile();
monte.cpp
//============================================================================
// Name : monte.cpp
// Author : Nazmus Saquib
// Version :
// Copyright :
// Description : BCA code in C++
//============================================================================
#include “Globals.h”
#include “scoef.h”
#include “rstop.h”
#include “muscle_bca.h”
#include “vectorGeometry.h”
const int numXBin = 100;
const int numIons = 1;
int xBin[numXBin+1] = {0};
int selectedXBin = 0;
double rho[4]={0.0};
int n[]={0,0,0,0};
double e0kev, m1, cw, ed, latticeConst;
int z1, hn, iy, nowout;
double dx[3] = {0.0};
int zt[3][7] = {0};
double mt[3][7] = {0.};
double t[3][7] = {0.};
int Layer; //use this for number of layers rather than the L in the program;
//remember this cannot be set to 0. Other loops/arrays may start from
//0, but keep this >= 1;
//the arrays..
double my[3][7]= {0},
ai[3][7]= {0},
fi[3][7]= {0},
ec[3][7]= {0},
io[3][7]= {0},
k[3]= {0},
kl[3][7]= {0};
double vf[3][7]= {0},
mu[3]= {0},
ioniz[3]= {0},
h[3]= {0},
xx[3]= {0},
m2[3]= {0.0},
z2[3]= {0},
c[3]= {0},
epsbk[3]= {0},
arho[3]= {0};
double a[3]= {0},
f[3]= {0},
lm[3]= {0},
pmax[3]= {0},
fd[3]= {0},
kd[3]= {0},
sbk[3]= {0},
lf[3]= {0},
yy[8]= {0};
double se[3][1000]= {0.0},
seo[1000]= {0.0},
epsdg[3]= {0.0};
double ls = 0., lo = 0., maximum = 0.;
double xsum = 0, x2sum = 0, x3sum = 0, x4sum = 0, plsum = 0, pl2sum = 0;
double avex = 0, vari = 0, sigma = 0, v = 0, v2 = 0, Gamma = 0, beta = 0, y = 0, avepl
= 0, sigpl = 0, avecol = 0;
int i = 0, j = 0;
int ib = 0, it = 0;
double eb = 0.0, et = 0.0;
int icsum = 0;
double y2sum = 0, xy2sum = 0, x2y2su = 0, y4sum = 0;
double tau = 0;
int iii = -1;
//my dummy vars
int w; double q;
//my customized data structures or vars
scoefData scoefz1;
rstopData rstp;
//these vars (continuing from this line) are added later as needed, vars that were not
declared in the initialization of trim85 but showed up in the middle.
double e0, ef;
int iz;
double alfa, alpha;
double tmin, da;
double L0;
int iz1;
double ee;
int izt;
double nh;
double epso;
int ih;
double e;
//boolean for keeping track of a particle being transmitted or backscattered
int transmitted = 0;
int backscattered = 0;
//boolean for keeping track of channeling
int insideChannel = 1;
//boolean for determining whether to scatter from neighbor atoms
int neighborFlag = 0;
//main function
int main()
{
cout << “Initializing” << endl;
Initialize(“IronInput.dat”);
calculateAvgMassOfLayer();
getStoppingForTarget();
setInitialConditions();
MonteCarlo();
/* *********************** Testing Ground for arrays and variables
******************** */
for (w = 1; w <= 8; w++) cout << “\t “ << yy[w];
for (w = 1; w <= 3; w++) cout << “\n\t “ << xx[w];
cout << “CW or L0: “ << L0;
//(trouble! The values of n[] elements are changing like crazy)
cout << endl << n[0] << “\t” << n[1] << “\t” << n[2] << “\t” << n[3] << endl;
cout << endl << rho[0] << “\t” << rho[1] << “\t” << rho[2] << “\t” << rho[3] <<
“\t” << rho[4] << endl;
//test z2[], m2[] arrays
for (w = 1; w <= Layer; w++) cout << “\t “ << z2[w];
for (w = 1; w <= Layer; w++) cout << “\n\t “ << m2[w];
//test the se values
cout << endl << se[1][1000] << “ “ << se[2][1000] << “ “ << se[3][1000] << endl;
//test the se[] values by printing 10th element from the array (to be implemented)
//for (w = 1; w <= 100; w++)
//{
//for (int sss = 1; sss <= 50; sss++)
//{
//cout << “\t” << mpart[w][sss];
//}
//}
/* *********************** End of Testing Ground ************************** */
cout << endl;
//Now print values of each bin in xBin
//for (w = 1; w <= numXBin; w++) cout << xBin[w] << “,”;
//print final x values
cout << endl;
cout << “Number of Backscattered Ions: “ << ib << endl;
cout << “Number of Transmitted Ions: “ << it << endl;
return 0;
}
//end of main
//Helper functions follow from here
//initialize variables and setup each layer over here
void Initialize(char* filename)
{
//Read command file
ifstream instream;
instream.open(filename,ios::in);
cout << filename;
if (!instream)
{
exitOnError(filename);
}
instream >> e0kev >> z1 >> m1 >> latticeConst >> hn >> cw >> ed >> iy >> nowout;
instream >> dx[1] >> rho[1];
instream >> zt[1][1] >> mt[1][1] >> t[1][1];
instream >> n[1];
instream >> dx[2] >> rho[2];
instream >> zt[2][1] >> mt[2][1] >> t[2][1];
instream >> n[2];
instream >> dx[3] >> rho[3];
instream >> zt[3][1] >> mt[3][1] >> t[3][1];
instream >> n[3];
for (w = 0; w <= 3; w++)
{ if (n[w] != 1) n[w] = 1; }
instream.close();
Layer = 3;
//done with primary (crude) setup, off to reading scoef.dat file
iz = z1;
getstructScoef(iz, scoefz1, “scoef1.dat”); //used to get pcoef data yy in trim85
//so we put the values in yy here immediately
for (w = 1; w <= 8; w++)
{ yy[w] = scoefz1.pcoef[w]; }
//note: although yy turns out to be just a dummy array
e0 = e0kev*1000; //convert to ev.
if (ed == 0.) ed = 25.0;
ef = Max(5.0, e0kev*0.1);
//alfa = angle of incidence, alpha = radian of alfa
alfa = 0.;
alpha = alfa*Pi/180;
tmin = 5.0;
tau = 0.0;
da = 3.0;
if (iy == 0) iy = 16381;
//now calculate the total depth of each layer = xx(l), and grid spacing cw
xx[1] = dx[1];
for (w = 2; w <= 3; w++) { xx[w] = dx[w] + xx[w-1]; }
if (cw == 0) cw = 0.01*xx[3];
L0 = cw;
//take care of any custom variable or struct I made
rstp.vfermi = 0.0; //set this to 0. for the time being (see log for explanation)
//now, off to avg mass of layer in the next void function
}
//avg mass and atomic number of each layer
void calculateAvgMassOfLayer()
{
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
h[LL] = h[LL] + t[LL][w];
//cout << “testing here..” << rstp.vfermi << endl;
}
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
t[LL][w] = t[LL][w]/h[LL];
m2[LL] = m2[LL] + t[LL][w] * mt[LL][w];
z2[LL] = z2[LL] + t[LL][w] * zt[LL][w];
//note: z2 wont be an integer once t has a value other than 1.0??
//so are we calculating average atomic number here? why?
}
}
//done with this, off to finding electronic stopping powers in the next function
}
void getStoppingForTarget()
{
iz1 = z1; ee = 0;
for (int LL = 1; LL <= Layer; LL++)
{
arho[LL] = rho[LL] * 0.6022/(m2[LL]);
mu[LL] = m1/(m2[LL]);
int ii = n[LL];
for (int nn = 1; nn <= ii; nn++)
{
//set rstp.se[1..1000] = 0. Clear it for the next loop
for (w = 1; w <= 1000; w++)
{ rstp.se[w] = 0.; }
izt = zt[LL][nn];
//calling getrstop now. units, lfctr, vfermi = 1 (doesnt matter)
getrStop(iz1, izt, e0kev, 1, 1., 1., rstp); //rstp defined in header
//set this anyway, though I dont calculate this in RSTOP
vf[LL][nn] = rstp.vfermi; //which is just set 0 in the struct def.
for (w = 1; w <= 1000; w++)
{
se[LL][w] = se[LL][w] + rstp.se[w] * t[LL][nn] * arho[LL];
}
}
}
//now, off to setting up initial conditions next function
}
void setInitialConditions()
{
nh = hn; //number of histories
for (int LL = 1; LL <= Layer; LL++)
{
a[LL] = 0.5292 * 0.8853 / ( pow(z1, 0.23) + pow(z2[LL], 0.23) );
//now calculate the mean flight path with the conditions given in trim85
f[LL] = a[LL] * m2[LL] / ( z1 * z2[LL] * 14.4 * (m1 + m2[LL] ) );
epso = e0 * f[LL];
epsdg[LL] = tmin * f[LL] * pow( (1.0 + mu[LL]) , 2) / (4.0 * mu[LL]);
fd[LL] = 0.01 * pow( z2[LL], (-7.0/3.0) );
kd[LL] = 0.1334 * pow ( z2[LL], (2.0/3.0) ) / sqrt( m2[LL] );
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
my[LL][w] = m1/mt[LL][w];
ec[LL][w] = 4.0 * my[LL][w] / pow( ( 1.0 + my[LL][w] ), 2);
ai[LL][w] = 0.5292 * 0.8853 / ( pow(z1,0.23) + pow(zt[LL][w],0.23) );
fi[LL][w] = ai[LL][w] * mt[LL][w] / ( z1 * zt[LL][w] * 14.4 * ( m1 + mt[LL][w] ) );
}
}
cout << “Setup finished. Starting Monte Carlo Loops..”;
//off to monte carlo loop in next routine
}
void MonteCarlo()
{
//custom variables and arrays for this section
double e;
double cosin = 0.0, siny = 0.0, sine = 0.0, cosy = 0.0;
double pl = 0.0;
int ic;
int LL = 1;
double eps;
double eeg;
double p;
double b;
int ie, ia; //not sure if ie or ia should be double. They are used to access elements
of the m[][] array at some point
double see;
double dee;
double s2, c2, ct, st;
double r, rr;
double ex1, ex2, ex3, ex4;
double v, v1;
double fr, fr1;
double q;
double roc, sqe;
double cc, aa, ff;
double delta, co;
double den;
double phi, psi;
double x1;
int ip;
//variables for crystal calculations
double sep = 0.0;
int ionCounter = 0;
double p1, p2;
double Theta = 0.0;
double rTheta = 0.0, rPhi = 0.0;
double thetaThreshold = 0.5;
double crystalMuonY = 0.0, crystalMuonZ = 0.0;
//amount of translations in y and z axes
double translationY = 0.0, translationZ = 0.0;
//Scatter Plot variables
const int numScatterPlotBins = 5;
double scatterPlot[numScatterPlotBins + 1] = {0.0};
//Vector declarations
//lattice constant of Target (input from file)
double latticeConstant = latticeConst;
Vector3 ions[4];
Vector3 ionsOrdered[4];
Vector3 neighborIonsBCC[14];
Vector3 neighborIonsFCC[14];
Vector3 ionTranslationY(0,translationY,0);
Vector3 ionTranslationZ(0,0,translationZ);
Vector3 unitzplus, unitzminus, unityplus, unityminus, unitxplus, unitxminus;
unitzplus.z = 1;
unitzminus.z = -1;
unityplus.y = 1;
unityminus.y = -1;
unitxplus.x = 1;
unitxminus.x = -1;
Vector3 initialDirection(1,0,0);
Vector3 d;
d.x = 1;
d *= latticeConstant/2;
Vector3 lx(latticeConstant/2, 0, 0);
Vector3 ly(0, latticeConstant/2, 0);
Vector3 lz(0, 0, latticeConstant/2);
Vector3 lambda;
Vector3 lambdaPrime;
Vector3 pVector;
Vector3 pUnitVector;
Vector3 sepVector;
Vector3 Di;
Vector3 DiPrev;
//Vector3 DiPrevToDi;
Vector3 delX;
Vector3 delX1, delX2;
Vector3 dummy1, dummy2, temp;
Vector3 scatterIonPos;
//initialize the random number generator
srand(time(NULL));
//open file to write output
ofstream outStream;
outStream.open(“coords0.txt”);
if(outStream.fail())
{
exitOnError(“Could not open Output file”);
}
//write basic information in the output file
//number of ions, ion energy, total depth, depth of each layer
outStream << nh << “\t” << e0kev << “\t” << xx[Layer] << “\t” << dx[1] << “\t”
<< dx[2] << “\t” << dx[3] << endl;
//open scatter plot file to write current Y and Z coordinates of muons at designated
intervals
ofstream scatterStream;
scatterStream.open(“scatterOut1.txt”);
if(scatterStream.fail())
{
exitOnError(“Could not open Scatter Plot Output file”);
}
//open range distribution file to write final X coordinates of muons
ofstream rangeStream;
rangeStream.open(“rangeOut1.txt”);
if(rangeStream.fail())
{
exitOnError(“Could not open Range Distribution Output file”);
}
//Open general information dump file
ofstream infoStream;
infoStream.open(“info1.txt”);
if(infoStream.fail())
{
exitOnError(“Could not open general information Output file”);
}
//Entering the target
//First set up for the top layer
for (ih = 1; ih <= nh; ih++)
{
avex = xsum / Max(1.0, (float)(ih - ib - it - 1));
if (talk == 2) cout << “Average ion range so far: “ << avex << “ angstroms.”
<<endl;
if (talk > 2) cout << “Now starting ion number “ << ih << endl;
e = e0;
//set scatterPlot array (the intervals)
scatterPlot[0] = 10;
scatterPlot[1] = 30;
scatterPlot[2] = 50;
scatterPlot[3] = 100;
scatterPlot[4] = 150;
scatterPlot[5] = 200;
/*
for(int ccc = 0; ccc <= numScatterPlotBins; ccc++)
{
cout << “scatter plot “ << ccc << “: “ << scatterPlot[ccc] << endl;
}
*/
//Initial Ion Positions
ions[0] = d + ionTranslationZ + unitzminus * (latticeConstant/2);
ions[1] = d + ionTranslationZ + unitzplus * (latticeConstant/2);
ions[2] = d * 2 + ionTranslationY + unityminus * (latticeConstant/2);
ions[3] = d * 2 + ionTranslationY + unityplus * (latticeConstant/2);
//Create a polygon that resides on the lateral axes.
//The points are put on anticlockwise order, which is important for
//testing whether the test point lies on this polygon
ionsOrdered[0] = ions[0];
ionsOrdered[1] = ions[2];
ionsOrdered[2] = ions[1];
ionsOrdered[3] = ions[3];
//generate random theta and phi angles.
rTheta = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * thetaThreshold;
rPhi = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * 2 * Pi;
//find corresponding x, y and z components of the direction vector.
//radius of the direction vector is 1
initialDirection.x = cos(rTheta);
initialDirection.z = sin(rTheta) * cos(rPhi);
initialDirection.y = sin(rTheta) * sin(rPhi);
//set the counter to 0 for a new ion
ionCounter = 0;
pl = 0.0;
ic = 0;
//set initial DiPrev - the origin
DiPrev.x = 0.0; DiPrev.y = 0.0; DiPrev.z = 0.0;
//set initial lambda, the direction of motion. Normalize it.
lambda.clear();
lambda = initialDirection;
lambda.normalize();
//set initial delX to origin
delX.clear();
//clear the dummy delX vectors, set them to origin
delX1.clear();
delX2.clear();
dummy1.clear();
dummy2.clear();
temp.clear();
LL = 1;
//set transmitted and backscattered to false
transmitted = 0;
backscattered = 0;
//set channeling to true
insideChannel = 1;
neighborFlag = 0;
//write the initial coordinates to the output file
outStream << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << endl << “Initial: “;
//cout << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << “r1 = “ << r1 << endl;
//cycle for each collision until the energy of the particle becomes too low, or
the particle backscatters, or it goes out of the last layer (transmission)
//needs a do while loop here,
//which I will mention as the ‘mother loop’ from now.
do
{
ic = ic + 1;
eps = e * f[LL];
eeg = sqrt(eps*epsdg[LL]);
//pmax[LL] = a[LL] / (eeg + sqrt(eeg) + 0.125 * pow( eeg, 0.1) );
pmax[LL] = sqrt(3) * (latticeConstant / 2) * 0.7;
//Calculate impact parameter and choose the atom to scatter from.
//Do this for ion pairs 0,1 and 2,3.
if (ionCounter == 0)
{
delX1 = ions[0] - DiPrev;
delX2 = ions[1] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[0];
ions[0] = ions[1];
ions[1] = temp;
//cout << “Vertical Ions swapped” << endl;
}
}
if (ionCounter == 2)
{
delX1 = ions[2] - DiPrev;
delX2 = ions[3] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[2];
ions[2] = ions[3];
ions[3] = temp;
//cout << “Horizontal Ions swapped” << endl;
}
}
//now calculate impact parameter
if(neighborFlag == 0)
{
delX = ions[ionCounter] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
else if(neighborFlag == 1)
{
double impact[13] = {0.0};
double radial[13] = {0.0};
double S[13] = {0.0};
double sumS = 0.0;
double Probability[13] = {0.0};
double rnd_candidate = 0.0;
int selected_candidate = -1;
for(int ncount = 0; ncount <= 13; ncount++)
{
delX = neighborIonsBCC[ncount] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
//scatterIonPos = neighborIonsBCC[ncount];
impact[ncount] = p;
radial[ncount] = delX.magnitude();
S[ncount] = 1 / ( pow(impact[ncount],2) * radial[ncount] );
sumS += S[ncount];
//general scheme of selecting the neighbor ion
// if(p < pmax[LL])
// {
// scatterIonPos = neighborIonsBCC[ncount];
// //cout << “Neighbor “ << ncount << “ is selected” << endl;
// break;
// }
}
for(int ncount = 0; ncount <= 13; ncount++)
{
Probability[ncount] = S[ncount] / sumS;
}
//print out the probability array
cout << endl;
for(int ncount = 0; ncount <= 13; ncount++)
{
//cout << Probability[ncount] << “ “;
infoStream << Probability[ncount] << “ “;
}
infoStream << endl;
//cout << endl;
//random number between 0 and 1
rnd_candidate = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) );
//cout << “rand_candidate: “ << rnd_candidate << endl;
//choose the candidate for scattering
selected_candidate = whichNonUniformBin(rnd_candidate, Probability, 13);
//cout << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate <<
endl;
infoStream << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate
<< endl;
//assign the scatterIonPos variable to the selected neighbor
scatterIonPos = neighborIonsBCC[selected_candidate];
//cout << “Scattering Ion Position: “; scatterIonPos.printVector();
//find the essential quantities for the selected neighbor
delX = neighborIonsBCC[selected_candidate] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
//find eps and b using fi[LL][nn], using nn that I was supposed to find from above
//here im deliberately using nn = 1
eps = fi[LL][1] * e;
b = p / ai[LL][1];
if (eps > 10) //rutherford scattering
{
s2 = 1.0 / (1.0 + (1.0 + b * (1.0 + b)) * pow((2.0 * eps * b), 2) );
c2 = 1.0 - s2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
else //magic formula
{
r = b;
rr = -2.7 * log(eps * b);
if (rr >= b)//note >= sign instead < in trim85
{
rr = -2.7 * log(eps * rr);
if (rr >= b)//note >= sign instead < in trim85
{
r = rr;
}
}
//do while loop that replaces line 330 loop
do
{
ex1 = 0.18175 * exp(-3.1998 * r);
ex2 = 0.50986 * exp(-0.94229 * r);
ex3 = 0.28022 * exp(-0.4029 * r);
ex4 = 0.028171 * exp(-0.20162 * r);
v = (ex1 + ex2 + ex3 + ex4) / r;
v1 = -(v + 3.1998 * ex1 + 0.94229 * ex2 + 0.4029 * ex3 + 0.20162 * ex4) / r;
fr = b * b / r + v * r / eps - r;
fr1 = -b * b / (r * r) + (v + v1 * r) / eps - 1.0;
q = fr / fr1;
r = r - q;
}
while( (Abs(q / r)) > 0.001 );
roc = -2.0 * (eps - v) / v1;
sqe = sqrt(eps);
//5 parameter magic scattering calculation
//below is for universal potential
cc = (0.011615 + sqe) / (0.0071222 + sqe);
aa = 2.0 * eps * (1.0 + (0.99229 / sqe) ) * ( pow(b, cc) );
ff = ( sqrt(aa * aa + 1.0) - aa) * ( (9.3066 + eps) / (14.813 + eps) );
delta = (r - b) * aa * ff / (ff + 1.0);
co = (b + delta + roc) / (r + roc);
c2 = co * co;
s2 = 1.0 - c2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
Theta = acos(ct);
//we are done finding theta (in CM system). So calculate all other quantities.
//find separation and the separation vector.
phi = (Pi - Theta) / 2;
sep = p / tan(phi);
sepVector = lambda * sep;
//find theta in laboratory frame - psi
psi = atan(st / (ct + my[LL][1] ) );
//note: change my[LL][1] to my[LL][nn] when the above section is fixed.
if (psi < 0 ) psi = psi + Pi; //should I do this for crystals?
//find Di, the scattering point vector
Di = DiPrev + delX + pVector - sepVector;
//find new direction of motion
lambdaPrime = lambda * cos(psi) + pUnitVector * sin(psi);
lambdaPrime.normalize();
//find length of step, ls = distance of Di from DiPrev
ls = Di.getDistance(DiPrev);
//find energy lost due to electronic stopping, dee
ie = (int)(e/e0kev+0.5); //should it be 0.5? or less so that ie <=1000?
see = se[LL][ie];
if (e < e0kev) see = se[LL][1] * sqrt(e/e0kev);
dee = ls * see;
// den = energy transferred to recoil
den = ec[LL][1] * s2 * e; //note: I am using ec[LL][1] here instead of [LL][nn].
//cout << “den = “ << den << “, dee = “ << dee << endl;
infoStream << “den = “ << den << “, dee = “ << dee << endl;
e = e - den - dee;
//cout << endl<< “current ion energy: “ << e << endl;
if (dee > maximum) maximum = dee;
pl = pl + ls - tau;
//write the ion position to output file
outStream << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
if((ic%30)==0)
{
//cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
}
//determine which scatter plot Di’s x value belongs to.
//output the y and z coordinates to scatter plot file accordingly.
for(int cc = 0; cc <= numScatterPlotBins; cc++)
{
if( Di.x >= (scatterPlot[cc]) )
{
crystalMuonY = Di.y - translationY;
crystalMuonZ = Di.z - translationZ;
//cout << “scatter plot “ << ct << “: “ << scatterPlot[ct] << endl;
scatterStream << scatterPlot[cc] << “\t” << crystalMuonY << “\t” <<
crystalMuonZ << endl;
//set scatterPlot[ss] to a big number
scatterPlot[cc] = 10000;
//break out of this for loop
break;
}
}
//determine if Di is in the channeling region.
//insideChannel = Di.isInsidePolygon(ionsOrdered, 4);
//break out of parent loop if not inside the channel
if(insideChannel == 0)
{
cout << “Ion “ << ih << “ is out of Channel” << endl;
cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
break;
}
//determine which layer the next collision will be in
if (Di.x < 0.0) //particle is backscattered
{
backscattered = 1; //cout << “ion number “ << ih << “ backscattered.” << endl;
infoStream << “ion number “ << ih << “ backscattered.” << endl;
ib = ib + 1;
eb = eb + e;
break; //break out of ‘mother do loop’ and continue with the next session of
for loop.
}
//here we set the current or next layer the particle will be in
for (w = 1; w <= Layer; w++)
{
if ( (Di.x <= xx[w]) && (w == 1) )
{
LL = 1;
//cout << endl<<”ion is in layer “ << LL << endl;
break;
//break out of this For loop and go check if the particle is transmitted.
}
else if ( (Di.x <= xx[w]) && (Di.x > xx[w-1]) )
{
LL = w;
//cout << “ion is in layer “ << LL <<endl;
break; //break out of this For loop and go check if the particle is
transmitted.
}
}
//now, check for particle transmission, i.e. whether the particle went out of the
last layer.
if(Di.x >= xx[Layer])
{
//particle is transmitted, take care of appropriate variables and break
transmitted = 1;//cout << “ion number “ << ih << “ transmitted.” << endl;
it = it + 1;
et = et + e;
ia = 57.295779 * acos(cosin) / da + 1.0;
ie = 100 * e / e0 + 1.0;
//m[ie][ia] = m[ie][ia] + 1;//note: how is this possible? ie and ia should be
integers in order to access the elements of the array m[][]. But we calculate them as
doubles here!
break; //break out of the ‘mother’ do loop
}
//now take care of ionCounter and other variables for the next scattering
if(neighborFlag == 0)
{
if(ionCounter == 3)
{
//ionCounter = 0;
neighborFlag = 1;
scatterIonPos = ions[3];
//cout << endl << “got out of first two layers” << endl;
}
else
{
ionCounter++;
}
}
if(neighborFlag == 1)
{
//cout << “Updating Neighbor Ions” << endl;
neighborIonsBCC[0] = scatterIonPos + lx - ly + lz;
neighborIonsBCC[1] = scatterIonPos + lx + ly + lz;
neighborIonsBCC[2] = scatterIonPos + lx + ly - lz;
neighborIonsBCC[3] = scatterIonPos + lx - ly - lz;
neighborIonsBCC[4] = scatterIonPos + lx * 2;
neighborIonsBCC[5] = scatterIonPos - lx - ly - lz;
neighborIonsBCC[6] = scatterIonPos - lx + ly - lz;
neighborIonsBCC[7] = scatterIonPos - lx + ly + lz;
neighborIonsBCC[8] = scatterIonPos - lx - ly + lz;
neighborIonsBCC[9] = scatterIonPos + lz * 2;
neighborIonsBCC[10] = scatterIonPos - lz * 2;
neighborIonsBCC[11] = scatterIonPos + ly * 2;
neighborIonsBCC[12] = scatterIonPos - ly * 2;
neighborIonsBCC[13] = scatterIonPos - lx * 2;
}
//set DiPrev to Di
DiPrev = Di;
//update current lambda to lambdaPrime
lambda = lambdaPrime;
//now the while condition of the mother do loop checks if the particle has lesser
energy than our lowest energy limit, ef.
}
while(e > ef);
//since we are out of the mother do loop now, the particle must have come to a
stop. So, increase the final particle distributions if the particle has not been
transmitted or backscattered.
if( ((transmitted == 0)) && ((backscattered == 0)) && ((insideChannel == 1)) )
{
ip = (int)(pl/cw + 1.0);
if(ip > 100) ip = 100;
//ipl[ip] = ipl[ip] + 1;
xsum = xsum + Di.x;
//my own bin function
selectedXBin = whichBin(Di.x, xx[Layer], numXBin);
//write the selected bin to the output file
//outStream << selectedXBin << endl;
//cout << x << endl << xx[Layer] << endl << numXBin << endl << selectedXBin;
xBin[selectedXBin] = xBin[selectedXBin] + 1;
//print final x value for plotting histogram
//cout << “ion “ << ih << “ final x: “ << Di.x << endl;
infoStream << “ion “ << ih << “ final x: “ << Di.x << endl;
//cout << Di.x << “,”;
rangeStream << Di.x << endl;
plsum = plsum + pl;
icsum = icsum + ic;
//ipl is the ion path length - the total avg. distance the ion travels
regardless of direction before it comes to stop
}
//that brings us to the end of one ion’s journey, now go to next ion by going back
to the for loop’s beginning..
}
//and this ends the monte carlo loop function. Take care of necessary structures and
variables that need to be cleared/deleted
outStream.close();
scatterStream.close();
infoStream << “Number of Backscattered Ions: “ << ib << endl;
infoStream.close();
rangeStream.close();
}
int whichNonUniformBin(double e, double arr[], int numBins)
{
double low = 0, high = arr[0];
if((e>=low) && (e<high))
return 0;
else
{
for(int i = 0; i < numBins; i++)
{
low += arr[i];
high += arr[i+1];
//cout << “\tlow: “ << low << “, high:” << high << endl;
if((e>=low) && (e<high))
return i;
}
}
}
126
//============================================================================
// Name : monte.cpp
// Author : Nazmus Saquib
// Version :
// Copyright :
// Description : BCA code in C++
//============================================================================
#include “Globals.h”
#include “scoef.h”
#include “rstop.h”
#include “muscle_bca.h”
#include “vectorGeometry.h”
const int numXBin = 100;
const int numIons = 1;
int xBin[numXBin+1] = {0};
int selectedXBin = 0;
double rho[4]={0.0};
int n[]={0,0,0,0};
double e0kev, m1, cw, ed, latticeConst;
int z1, hn, iy, nowout;
double dx[3] = {0.0};
int zt[3][7] = {0};
double mt[3][7] = {0.};
double t[3][7] = {0.};
int Layer; //use this for number of layers rather than the L in the program;
//remember this cannot be set to 0. Other loops/arrays may start from
//0, but keep this >= 1;
//the arrays..
double my[3][7]= {0},
ai[3][7]= {0},
fi[3][7]= {0},
ec[3][7]= {0},
io[3][7]= {0},
k[3]= {0},
kl[3][7]= {0};
double vf[3][7]= {0},
mu[3]= {0},
ioniz[3]= {0},
h[3]= {0},
xx[3]= {0},
m2[3]= {0.0},
z2[3]= {0},
c[3]= {0},
epsbk[3]= {0},
arho[3]= {0};
double a[3]= {0},
f[3]= {0},
lm[3]= {0},
pmax[3]= {0},
fd[3]= {0},
kd[3]= {0},
sbk[3]= {0},
lf[3]= {0},
yy[8]= {0};
double se[3][1000]= {0.0},
seo[1000]= {0.0},
epsdg[3]= {0.0};
double ls = 0., lo = 0., maximum = 0.;
double xsum = 0, x2sum = 0, x3sum = 0, x4sum = 0, plsum = 0, pl2sum = 0;
double avex = 0, vari = 0, sigma = 0, v = 0, v2 = 0, Gamma = 0, beta = 0, y = 0, avepl
= 0, sigpl = 0, avecol = 0;
int i = 0, j = 0;
int ib = 0, it = 0;
double eb = 0.0, et = 0.0;
int icsum = 0;
double y2sum = 0, xy2sum = 0, x2y2su = 0, y4sum = 0;
double tau = 0;
int iii = -1;
//my dummy vars
int w; double q;
//my customized data structures or vars
scoefData scoefz1;
rstopData rstp;
//these vars (continuing from this line) are added later as needed, vars that were not
declared in the initialization of trim85 but showed up in the middle.
double e0, ef;
int iz;
double alfa, alpha;
double tmin, da;
double L0;
int iz1;
double ee;
int izt;
double nh;
double epso;
int ih;
double e;
//boolean for keeping track of a particle being transmitted or backscattered
int transmitted = 0;
int backscattered = 0;
//boolean for keeping track of channeling
int insideChannel = 1;
//boolean for determining whether to scatter from neighbor atoms
int neighborFlag = 0;
//main function
int main()
{
cout << “Initializing” << endl;
Initialize(“IronInput.dat”);
calculateAvgMassOfLayer();
getStoppingForTarget();
setInitialConditions();
MonteCarlo();
/* *********************** Testing Ground for arrays and variables
******************** */
for (w = 1; w <= 8; w++) cout << “\t “ << yy[w];
for (w = 1; w <= 3; w++) cout << “\n\t “ << xx[w];
cout << “CW or L0: “ << L0;
//(trouble! The values of n[] elements are changing like crazy)
cout << endl << n[0] << “\t” << n[1] << “\t” << n[2] << “\t” << n[3] << endl;
cout << endl << rho[0] << “\t” << rho[1] << “\t” << rho[2] << “\t” << rho[3] <<
“\t” << rho[4] << endl;
//test z2[], m2[] arrays
for (w = 1; w <= Layer; w++) cout << “\t “ << z2[w];
for (w = 1; w <= Layer; w++) cout << “\n\t “ << m2[w];
//test the se values
cout << endl << se[1][1000] << “ “ << se[2][1000] << “ “ << se[3][1000] << endl;
//test the se[] values by printing 10th element from the array (to be implemented)
//for (w = 1; w <= 100; w++)
//{
//for (int sss = 1; sss <= 50; sss++)
//{
//cout << “\t” << mpart[w][sss];
//}
//}
/* *********************** End of Testing Ground ************************** */
cout << endl;
//Now print values of each bin in xBin
//for (w = 1; w <= numXBin; w++) cout << xBin[w] << “,”;
//print final x values
cout << endl;
cout << “Number of Backscattered Ions: “ << ib << endl;
cout << “Number of Transmitted Ions: “ << it << endl;
return 0;
}
//end of main
//Helper functions follow from here
//initialize variables and setup each layer over here
void Initialize(char* filename)
{
//Read command file
ifstream instream;
instream.open(filename,ios::in);
cout << filename;
if (!instream)
{
exitOnError(filename);
}
instream >> e0kev >> z1 >> m1 >> latticeConst >> hn >> cw >> ed >> iy >> nowout;
instream >> dx[1] >> rho[1];
instream >> zt[1][1] >> mt[1][1] >> t[1][1];
instream >> n[1];
instream >> dx[2] >> rho[2];
instream >> zt[2][1] >> mt[2][1] >> t[2][1];
instream >> n[2];
instream >> dx[3] >> rho[3];
instream >> zt[3][1] >> mt[3][1] >> t[3][1];
instream >> n[3];
for (w = 0; w <= 3; w++)
{ if (n[w] != 1) n[w] = 1; }
instream.close();
Layer = 3;
//done with primary (crude) setup, off to reading scoef.dat file
iz = z1;
getstructScoef(iz, scoefz1, “scoef1.dat”); //used to get pcoef data yy in trim85
//so we put the values in yy here immediately
for (w = 1; w <= 8; w++)
{ yy[w] = scoefz1.pcoef[w]; }
//note: although yy turns out to be just a dummy array
e0 = e0kev*1000; //convert to ev.
if (ed == 0.) ed = 25.0;
ef = Max(5.0, e0kev*0.1);
//alfa = angle of incidence, alpha = radian of alfa
alfa = 0.;
alpha = alfa*Pi/180;
tmin = 5.0;
tau = 0.0;
da = 3.0;
if (iy == 0) iy = 16381;
//now calculate the total depth of each layer = xx(l), and grid spacing cw
xx[1] = dx[1];
for (w = 2; w <= 3; w++) { xx[w] = dx[w] + xx[w-1]; }
if (cw == 0) cw = 0.01*xx[3];
L0 = cw;
//take care of any custom variable or struct I made
rstp.vfermi = 0.0; //set this to 0. for the time being (see log for explanation)
//now, off to avg mass of layer in the next void function
}
//avg mass and atomic number of each layer
void calculateAvgMassOfLayer()
{
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
h[LL] = h[LL] + t[LL][w];
//cout << “testing here..” << rstp.vfermi << endl;
}
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
t[LL][w] = t[LL][w]/h[LL];
m2[LL] = m2[LL] + t[LL][w] * mt[LL][w];
z2[LL] = z2[LL] + t[LL][w] * zt[LL][w];
//note: z2 wont be an integer once t has a value other than 1.0??
//so are we calculating average atomic number here? why?
}
}
//done with this, off to finding electronic stopping powers in the next function
}
void getStoppingForTarget()
{
iz1 = z1; ee = 0;
for (int LL = 1; LL <= Layer; LL++)
{
arho[LL] = rho[LL] * 0.6022/(m2[LL]);
mu[LL] = m1/(m2[LL]);
int ii = n[LL];
for (int nn = 1; nn <= ii; nn++)
{
//set rstp.se[1..1000] = 0. Clear it for the next loop
for (w = 1; w <= 1000; w++)
{ rstp.se[w] = 0.; }
izt = zt[LL][nn];
//calling getrstop now. units, lfctr, vfermi = 1 (doesnt matter)
getrStop(iz1, izt, e0kev, 1, 1., 1., rstp); //rstp defined in header
//set this anyway, though I dont calculate this in RSTOP
vf[LL][nn] = rstp.vfermi; //which is just set 0 in the struct def.
for (w = 1; w <= 1000; w++)
{
se[LL][w] = se[LL][w] + rstp.se[w] * t[LL][nn] * arho[LL];
}
}
}
//now, off to setting up initial conditions next function
}
void setInitialConditions()
{
nh = hn; //number of histories
for (int LL = 1; LL <= Layer; LL++)
{
a[LL] = 0.5292 * 0.8853 / ( pow(z1, 0.23) + pow(z2[LL], 0.23) );
//now calculate the mean flight path with the conditions given in trim85
f[LL] = a[LL] * m2[LL] / ( z1 * z2[LL] * 14.4 * (m1 + m2[LL] ) );
epso = e0 * f[LL];
epsdg[LL] = tmin * f[LL] * pow( (1.0 + mu[LL]) , 2) / (4.0 * mu[LL]);
fd[LL] = 0.01 * pow( z2[LL], (-7.0/3.0) );
kd[LL] = 0.1334 * pow ( z2[LL], (2.0/3.0) ) / sqrt( m2[LL] );
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
my[LL][w] = m1/mt[LL][w];
ec[LL][w] = 4.0 * my[LL][w] / pow( ( 1.0 + my[LL][w] ), 2);
ai[LL][w] = 0.5292 * 0.8853 / ( pow(z1,0.23) + pow(zt[LL][w],0.23) );
fi[LL][w] = ai[LL][w] * mt[LL][w] / ( z1 * zt[LL][w] * 14.4 * ( m1 + mt[LL][w] ) );
}
}
cout << “Setup finished. Starting Monte Carlo Loops..”;
//off to monte carlo loop in next routine
}
void MonteCarlo()
{
//custom variables and arrays for this section
double e;
double cosin = 0.0, siny = 0.0, sine = 0.0, cosy = 0.0;
double pl = 0.0;
int ic;
int LL = 1;
double eps;
double eeg;
double p;
double b;
int ie, ia; //not sure if ie or ia should be double. They are used to access elements
of the m[][] array at some point
double see;
double dee;
double s2, c2, ct, st;
double r, rr;
double ex1, ex2, ex3, ex4;
double v, v1;
double fr, fr1;
double q;
double roc, sqe;
double cc, aa, ff;
double delta, co;
double den;
double phi, psi;
double x1;
int ip;
//variables for crystal calculations
double sep = 0.0;
int ionCounter = 0;
double p1, p2;
double Theta = 0.0;
double rTheta = 0.0, rPhi = 0.0;
double thetaThreshold = 0.5;
double crystalMuonY = 0.0, crystalMuonZ = 0.0;
//amount of translations in y and z axes
double translationY = 0.0, translationZ = 0.0;
//Scatter Plot variables
const int numScatterPlotBins = 5;
double scatterPlot[numScatterPlotBins + 1] = {0.0};
//Vector declarations
//lattice constant of Target (input from file)
double latticeConstant = latticeConst;
Vector3 ions[4];
Vector3 ionsOrdered[4];
Vector3 neighborIonsBCC[14];
Vector3 neighborIonsFCC[14];
Vector3 ionTranslationY(0,translationY,0);
Vector3 ionTranslationZ(0,0,translationZ);
Vector3 unitzplus, unitzminus, unityplus, unityminus, unitxplus, unitxminus;
unitzplus.z = 1;
unitzminus.z = -1;
unityplus.y = 1;
unityminus.y = -1;
unitxplus.x = 1;
unitxminus.x = -1;
Vector3 initialDirection(1,0,0);
Vector3 d;
d.x = 1;
d *= latticeConstant/2;
Vector3 lx(latticeConstant/2, 0, 0);
Vector3 ly(0, latticeConstant/2, 0);
Vector3 lz(0, 0, latticeConstant/2);
Vector3 lambda;
Vector3 lambdaPrime;
Vector3 pVector;
Vector3 pUnitVector;
Vector3 sepVector;
Vector3 Di;
Vector3 DiPrev;
//Vector3 DiPrevToDi;
Vector3 delX;
Vector3 delX1, delX2;
Vector3 dummy1, dummy2, temp;
Vector3 scatterIonPos;
//initialize the random number generator
srand(time(NULL));
//open file to write output
ofstream outStream;
outStream.open(“coords0.txt”);
if(outStream.fail())
{
exitOnError(“Could not open Output file”);
}
//write basic information in the output file
//number of ions, ion energy, total depth, depth of each layer
outStream << nh << “\t” << e0kev << “\t” << xx[Layer] << “\t” << dx[1] << “\t”
<< dx[2] << “\t” << dx[3] << endl;
//open scatter plot file to write current Y and Z coordinates of muons at designated
intervals
ofstream scatterStream;
scatterStream.open(“scatterOut1.txt”);
if(scatterStream.fail())
{
exitOnError(“Could not open Scatter Plot Output file”);
}
//open range distribution file to write final X coordinates of muons
ofstream rangeStream;
rangeStream.open(“rangeOut1.txt”);
if(rangeStream.fail())
{
exitOnError(“Could not open Range Distribution Output file”);
}
//Open general information dump file
ofstream infoStream;
infoStream.open(“info1.txt”);
if(infoStream.fail())
{
exitOnError(“Could not open general information Output file”);
}
//Entering the target
//First set up for the top layer
for (ih = 1; ih <= nh; ih++)
{
avex = xsum / Max(1.0, (float)(ih - ib - it - 1));
if (talk == 2) cout << “Average ion range so far: “ << avex << “ angstroms.”
<<endl;
if (talk > 2) cout << “Now starting ion number “ << ih << endl;
e = e0;
//set scatterPlot array (the intervals)
scatterPlot[0] = 10;
scatterPlot[1] = 30;
scatterPlot[2] = 50;
scatterPlot[3] = 100;
scatterPlot[4] = 150;
scatterPlot[5] = 200;
/*
for(int ccc = 0; ccc <= numScatterPlotBins; ccc++)
{
cout << “scatter plot “ << ccc << “: “ << scatterPlot[ccc] << endl;
}
*/
//Initial Ion Positions
ions[0] = d + ionTranslationZ + unitzminus * (latticeConstant/2);
ions[1] = d + ionTranslationZ + unitzplus * (latticeConstant/2);
ions[2] = d * 2 + ionTranslationY + unityminus * (latticeConstant/2);
ions[3] = d * 2 + ionTranslationY + unityplus * (latticeConstant/2);
//Create a polygon that resides on the lateral axes.
//The points are put on anticlockwise order, which is important for
//testing whether the test point lies on this polygon
ionsOrdered[0] = ions[0];
ionsOrdered[1] = ions[2];
ionsOrdered[2] = ions[1];
ionsOrdered[3] = ions[3];
//generate random theta and phi angles.
rTheta = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * thetaThreshold;
rPhi = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * 2 * Pi;
//find corresponding x, y and z components of the direction vector.
//radius of the direction vector is 1
initialDirection.x = cos(rTheta);
initialDirection.z = sin(rTheta) * cos(rPhi);
initialDirection.y = sin(rTheta) * sin(rPhi);
//set the counter to 0 for a new ion
ionCounter = 0;
pl = 0.0;
ic = 0;
//set initial DiPrev - the origin
DiPrev.x = 0.0; DiPrev.y = 0.0; DiPrev.z = 0.0;
//set initial lambda, the direction of motion. Normalize it.
lambda.clear();
lambda = initialDirection;
lambda.normalize();
//set initial delX to origin
delX.clear();
//clear the dummy delX vectors, set them to origin
delX1.clear();
delX2.clear();
dummy1.clear();
dummy2.clear();
temp.clear();
LL = 1;
//set transmitted and backscattered to false
transmitted = 0;
backscattered = 0;
//set channeling to true
insideChannel = 1;
neighborFlag = 0;
//write the initial coordinates to the output file
outStream << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << endl << “Initial: “;
//cout << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << “r1 = “ << r1 << endl;
//cycle for each collision until the energy of the particle becomes too low, or
the particle backscatters, or it goes out of the last layer (transmission)
//needs a do while loop here,
//which I will mention as the ‘mother loop’ from now.
do
{
ic = ic + 1;
eps = e * f[LL];
eeg = sqrt(eps*epsdg[LL]);
//pmax[LL] = a[LL] / (eeg + sqrt(eeg) + 0.125 * pow( eeg, 0.1) );
pmax[LL] = sqrt(3) * (latticeConstant / 2) * 0.7;
//Calculate impact parameter and choose the atom to scatter from.
//Do this for ion pairs 0,1 and 2,3.
if (ionCounter == 0)
{
delX1 = ions[0] - DiPrev;
delX2 = ions[1] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[0];
ions[0] = ions[1];
ions[1] = temp;
//cout << “Vertical Ions swapped” << endl;
}
}
if (ionCounter == 2)
{
delX1 = ions[2] - DiPrev;
delX2 = ions[3] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[2];
ions[2] = ions[3];
ions[3] = temp;
//cout << “Horizontal Ions swapped” << endl;
}
}
//now calculate impact parameter
if(neighborFlag == 0)
{
delX = ions[ionCounter] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
else if(neighborFlag == 1)
{
double impact[13] = {0.0};
double radial[13] = {0.0};
double S[13] = {0.0};
double sumS = 0.0;
double Probability[13] = {0.0};
double rnd_candidate = 0.0;
int selected_candidate = -1;
for(int ncount = 0; ncount <= 13; ncount++)
{
delX = neighborIonsBCC[ncount] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
//scatterIonPos = neighborIonsBCC[ncount];
impact[ncount] = p;
radial[ncount] = delX.magnitude();
S[ncount] = 1 / ( pow(impact[ncount],2) * radial[ncount] );
sumS += S[ncount];
//general scheme of selecting the neighbor ion
// if(p < pmax[LL])
// {
// scatterIonPos = neighborIonsBCC[ncount];
// //cout << “Neighbor “ << ncount << “ is selected” << endl;
// break;
// }
}
for(int ncount = 0; ncount <= 13; ncount++)
{
Probability[ncount] = S[ncount] / sumS;
}
//print out the probability array
cout << endl;
for(int ncount = 0; ncount <= 13; ncount++)
{
//cout << Probability[ncount] << “ “;
infoStream << Probability[ncount] << “ “;
}
infoStream << endl;
//cout << endl;
//random number between 0 and 1
rnd_candidate = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) );
//cout << “rand_candidate: “ << rnd_candidate << endl;
//choose the candidate for scattering
selected_candidate = whichNonUniformBin(rnd_candidate, Probability, 13);
//cout << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate <<
endl;
infoStream << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate
<< endl;
//assign the scatterIonPos variable to the selected neighbor
scatterIonPos = neighborIonsBCC[selected_candidate];
//cout << “Scattering Ion Position: “; scatterIonPos.printVector();
//find the essential quantities for the selected neighbor
delX = neighborIonsBCC[selected_candidate] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
//find eps and b using fi[LL][nn], using nn that I was supposed to find from above
//here im deliberately using nn = 1
eps = fi[LL][1] * e;
b = p / ai[LL][1];
if (eps > 10) //rutherford scattering
{
s2 = 1.0 / (1.0 + (1.0 + b * (1.0 + b)) * pow((2.0 * eps * b), 2) );
c2 = 1.0 - s2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
else //magic formula
{
r = b;
rr = -2.7 * log(eps * b);
if (rr >= b)//note >= sign instead < in trim85
{
rr = -2.7 * log(eps * rr);
if (rr >= b)//note >= sign instead < in trim85
{
r = rr;
}
}
//do while loop that replaces line 330 loop
do
{
ex1 = 0.18175 * exp(-3.1998 * r);
ex2 = 0.50986 * exp(-0.94229 * r);
ex3 = 0.28022 * exp(-0.4029 * r);
ex4 = 0.028171 * exp(-0.20162 * r);
v = (ex1 + ex2 + ex3 + ex4) / r;
v1 = -(v + 3.1998 * ex1 + 0.94229 * ex2 + 0.4029 * ex3 + 0.20162 * ex4) / r;
fr = b * b / r + v * r / eps - r;
fr1 = -b * b / (r * r) + (v + v1 * r) / eps - 1.0;
q = fr / fr1;
r = r - q;
}
while( (Abs(q / r)) > 0.001 );
roc = -2.0 * (eps - v) / v1;
sqe = sqrt(eps);
//5 parameter magic scattering calculation
//below is for universal potential
cc = (0.011615 + sqe) / (0.0071222 + sqe);
aa = 2.0 * eps * (1.0 + (0.99229 / sqe) ) * ( pow(b, cc) );
ff = ( sqrt(aa * aa + 1.0) - aa) * ( (9.3066 + eps) / (14.813 + eps) );
delta = (r - b) * aa * ff / (ff + 1.0);
co = (b + delta + roc) / (r + roc);
c2 = co * co;
s2 = 1.0 - c2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
Theta = acos(ct);
//we are done finding theta (in CM system). So calculate all other quantities.
//find separation and the separation vector.
phi = (Pi - Theta) / 2;
sep = p / tan(phi);
sepVector = lambda * sep;
//find theta in laboratory frame - psi
psi = atan(st / (ct + my[LL][1] ) );
//note: change my[LL][1] to my[LL][nn] when the above section is fixed.
if (psi < 0 ) psi = psi + Pi; //should I do this for crystals?
//find Di, the scattering point vector
Di = DiPrev + delX + pVector - sepVector;
//find new direction of motion
lambdaPrime = lambda * cos(psi) + pUnitVector * sin(psi);
lambdaPrime.normalize();
//find length of step, ls = distance of Di from DiPrev
ls = Di.getDistance(DiPrev);
//find energy lost due to electronic stopping, dee
ie = (int)(e/e0kev+0.5); //should it be 0.5? or less so that ie <=1000?
see = se[LL][ie];
if (e < e0kev) see = se[LL][1] * sqrt(e/e0kev);
dee = ls * see;
// den = energy transferred to recoil
den = ec[LL][1] * s2 * e; //note: I am using ec[LL][1] here instead of [LL][nn].
//cout << “den = “ << den << “, dee = “ << dee << endl;
infoStream << “den = “ << den << “, dee = “ << dee << endl;
e = e - den - dee;
//cout << endl<< “current ion energy: “ << e << endl;
if (dee > maximum) maximum = dee;
pl = pl + ls - tau;
//write the ion position to output file
outStream << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
if((ic%30)==0)
{
//cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
}
//determine which scatter plot Di’s x value belongs to.
//output the y and z coordinates to scatter plot file accordingly.
for(int cc = 0; cc <= numScatterPlotBins; cc++)
{
if( Di.x >= (scatterPlot[cc]) )
{
crystalMuonY = Di.y - translationY;
crystalMuonZ = Di.z - translationZ;
//cout << “scatter plot “ << ct << “: “ << scatterPlot[ct] << endl;
scatterStream << scatterPlot[cc] << “\t” << crystalMuonY << “\t” <<
crystalMuonZ << endl;
//set scatterPlot[ss] to a big number
scatterPlot[cc] = 10000;
//break out of this for loop
break;
}
}
//determine if Di is in the channeling region.
//insideChannel = Di.isInsidePolygon(ionsOrdered, 4);
//break out of parent loop if not inside the channel
if(insideChannel == 0)
{
cout << “Ion “ << ih << “ is out of Channel” << endl;
cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
break;
}
//determine which layer the next collision will be in
if (Di.x < 0.0) //particle is backscattered
{
backscattered = 1; //cout << “ion number “ << ih << “ backscattered.” << endl;
infoStream << “ion number “ << ih << “ backscattered.” << endl;
ib = ib + 1;
eb = eb + e;
break; //break out of ‘mother do loop’ and continue with the next session of
for loop.
}
//here we set the current or next layer the particle will be in
for (w = 1; w <= Layer; w++)
{
if ( (Di.x <= xx[w]) && (w == 1) )
{
LL = 1;
//cout << endl<<”ion is in layer “ << LL << endl;
break;
//break out of this For loop and go check if the particle is transmitted.
}
else if ( (Di.x <= xx[w]) && (Di.x > xx[w-1]) )
{
LL = w;
//cout << “ion is in layer “ << LL <<endl;
break; //break out of this For loop and go check if the particle is
transmitted.
}
}
//now, check for particle transmission, i.e. whether the particle went out of the
last layer.
if(Di.x >= xx[Layer])
{
//particle is transmitted, take care of appropriate variables and break
transmitted = 1;//cout << “ion number “ << ih << “ transmitted.” << endl;
it = it + 1;
et = et + e;
ia = 57.295779 * acos(cosin) / da + 1.0;
ie = 100 * e / e0 + 1.0;
//m[ie][ia] = m[ie][ia] + 1;//note: how is this possible? ie and ia should be
integers in order to access the elements of the array m[][]. But we calculate them as
doubles here!
break; //break out of the ‘mother’ do loop
}
//now take care of ionCounter and other variables for the next scattering
if(neighborFlag == 0)
{
if(ionCounter == 3)
{
//ionCounter = 0;
neighborFlag = 1;
scatterIonPos = ions[3];
//cout << endl << “got out of first two layers” << endl;
}
else
{
ionCounter++;
}
}
if(neighborFlag == 1)
{
//cout << “Updating Neighbor Ions” << endl;
neighborIonsBCC[0] = scatterIonPos + lx - ly + lz;
neighborIonsBCC[1] = scatterIonPos + lx + ly + lz;
neighborIonsBCC[2] = scatterIonPos + lx + ly - lz;
neighborIonsBCC[3] = scatterIonPos + lx - ly - lz;
neighborIonsBCC[4] = scatterIonPos + lx * 2;
neighborIonsBCC[5] = scatterIonPos - lx - ly - lz;
neighborIonsBCC[6] = scatterIonPos - lx + ly - lz;
neighborIonsBCC[7] = scatterIonPos - lx + ly + lz;
neighborIonsBCC[8] = scatterIonPos - lx - ly + lz;
neighborIonsBCC[9] = scatterIonPos + lz * 2;
neighborIonsBCC[10] = scatterIonPos - lz * 2;
neighborIonsBCC[11] = scatterIonPos + ly * 2;
neighborIonsBCC[12] = scatterIonPos - ly * 2;
neighborIonsBCC[13] = scatterIonPos - lx * 2;
}
//set DiPrev to Di
DiPrev = Di;
//update current lambda to lambdaPrime
lambda = lambdaPrime;
//now the while condition of the mother do loop checks if the particle has lesser
energy than our lowest energy limit, ef.
}
while(e > ef);
//since we are out of the mother do loop now, the particle must have come to a
stop. So, increase the final particle distributions if the particle has not been
transmitted or backscattered.
if( ((transmitted == 0)) && ((backscattered == 0)) && ((insideChannel == 1)) )
{
ip = (int)(pl/cw + 1.0);
if(ip > 100) ip = 100;
//ipl[ip] = ipl[ip] + 1;
xsum = xsum + Di.x;
//my own bin function
selectedXBin = whichBin(Di.x, xx[Layer], numXBin);
//write the selected bin to the output file
//outStream << selectedXBin << endl;
//cout << x << endl << xx[Layer] << endl << numXBin << endl << selectedXBin;
xBin[selectedXBin] = xBin[selectedXBin] + 1;
//print final x value for plotting histogram
//cout << “ion “ << ih << “ final x: “ << Di.x << endl;
infoStream << “ion “ << ih << “ final x: “ << Di.x << endl;
//cout << Di.x << “,”;
rangeStream << Di.x << endl;
plsum = plsum + pl;
icsum = icsum + ic;
//ipl is the ion path length - the total avg. distance the ion travels
regardless of direction before it comes to stop
}
//that brings us to the end of one ion’s journey, now go to next ion by going back
to the for loop’s beginning..
}
//and this ends the monte carlo loop function. Take care of necessary structures and
variables that need to be cleared/deleted
outStream.close();
scatterStream.close();
infoStream << “Number of Backscattered Ions: “ << ib << endl;
infoStream.close();
rangeStream.close();
}
int whichNonUniformBin(double e, double arr[], int numBins)
{
double low = 0, high = arr[0];
if((e>=low) && (e<high))
return 0;
else
{
for(int i = 0; i < numBins; i++)
{
low += arr[i];
high += arr[i+1];
//cout << “\tlow: “ << low << “, high:” << high << endl;
if((e>=low) && (e<high))
return i;
}
}
}
127
//============================================================================
// Name : monte.cpp
// Author : Nazmus Saquib
// Version :
// Copyright :
// Description : BCA code in C++
//============================================================================
#include “Globals.h”
#include “scoef.h”
#include “rstop.h”
#include “muscle_bca.h”
#include “vectorGeometry.h”
const int numXBin = 100;
const int numIons = 1;
int xBin[numXBin+1] = {0};
int selectedXBin = 0;
double rho[4]={0.0};
int n[]={0,0,0,0};
double e0kev, m1, cw, ed, latticeConst;
int z1, hn, iy, nowout;
double dx[3] = {0.0};
int zt[3][7] = {0};
double mt[3][7] = {0.};
double t[3][7] = {0.};
int Layer; //use this for number of layers rather than the L in the program;
//remember this cannot be set to 0. Other loops/arrays may start from
//0, but keep this >= 1;
//the arrays..
double my[3][7]= {0},
ai[3][7]= {0},
fi[3][7]= {0},
ec[3][7]= {0},
io[3][7]= {0},
k[3]= {0},
kl[3][7]= {0};
double vf[3][7]= {0},
mu[3]= {0},
ioniz[3]= {0},
h[3]= {0},
xx[3]= {0},
m2[3]= {0.0},
z2[3]= {0},
c[3]= {0},
epsbk[3]= {0},
arho[3]= {0};
double a[3]= {0},
f[3]= {0},
lm[3]= {0},
pmax[3]= {0},
fd[3]= {0},
kd[3]= {0},
sbk[3]= {0},
lf[3]= {0},
yy[8]= {0};
double se[3][1000]= {0.0},
seo[1000]= {0.0},
epsdg[3]= {0.0};
double ls = 0., lo = 0., maximum = 0.;
double xsum = 0, x2sum = 0, x3sum = 0, x4sum = 0, plsum = 0, pl2sum = 0;
double avex = 0, vari = 0, sigma = 0, v = 0, v2 = 0, Gamma = 0, beta = 0, y = 0, avepl
= 0, sigpl = 0, avecol = 0;
int i = 0, j = 0;
int ib = 0, it = 0;
double eb = 0.0, et = 0.0;
int icsum = 0;
double y2sum = 0, xy2sum = 0, x2y2su = 0, y4sum = 0;
double tau = 0;
int iii = -1;
//my dummy vars
int w; double q;
//my customized data structures or vars
scoefData scoefz1;
rstopData rstp;
//these vars (continuing from this line) are added later as needed, vars that were not
declared in the initialization of trim85 but showed up in the middle.
double e0, ef;
int iz;
double alfa, alpha;
double tmin, da;
double L0;
int iz1;
double ee;
int izt;
double nh;
double epso;
int ih;
double e;
//boolean for keeping track of a particle being transmitted or backscattered
int transmitted = 0;
int backscattered = 0;
//boolean for keeping track of channeling
int insideChannel = 1;
//boolean for determining whether to scatter from neighbor atoms
int neighborFlag = 0;
//main function
int main()
{
cout << “Initializing” << endl;
Initialize(“IronInput.dat”);
calculateAvgMassOfLayer();
getStoppingForTarget();
setInitialConditions();
MonteCarlo();
/* *********************** Testing Ground for arrays and variables
******************** */
for (w = 1; w <= 8; w++) cout << “\t “ << yy[w];
for (w = 1; w <= 3; w++) cout << “\n\t “ << xx[w];
cout << “CW or L0: “ << L0;
//(trouble! The values of n[] elements are changing like crazy)
cout << endl << n[0] << “\t” << n[1] << “\t” << n[2] << “\t” << n[3] << endl;
cout << endl << rho[0] << “\t” << rho[1] << “\t” << rho[2] << “\t” << rho[3] <<
“\t” << rho[4] << endl;
//test z2[], m2[] arrays
for (w = 1; w <= Layer; w++) cout << “\t “ << z2[w];
for (w = 1; w <= Layer; w++) cout << “\n\t “ << m2[w];
//test the se values
cout << endl << se[1][1000] << “ “ << se[2][1000] << “ “ << se[3][1000] << endl;
//test the se[] values by printing 10th element from the array (to be implemented)
//for (w = 1; w <= 100; w++)
//{
//for (int sss = 1; sss <= 50; sss++)
//{
//cout << “\t” << mpart[w][sss];
//}
//}
/* *********************** End of Testing Ground ************************** */
cout << endl;
//Now print values of each bin in xBin
//for (w = 1; w <= numXBin; w++) cout << xBin[w] << “,”;
//print final x values
cout << endl;
cout << “Number of Backscattered Ions: “ << ib << endl;
cout << “Number of Transmitted Ions: “ << it << endl;
return 0;
}
//end of main
//Helper functions follow from here
//initialize variables and setup each layer over here
void Initialize(char* filename)
{
//Read command file
ifstream instream;
instream.open(filename,ios::in);
cout << filename;
if (!instream)
{
exitOnError(filename);
}
instream >> e0kev >> z1 >> m1 >> latticeConst >> hn >> cw >> ed >> iy >> nowout;
instream >> dx[1] >> rho[1];
instream >> zt[1][1] >> mt[1][1] >> t[1][1];
instream >> n[1];
instream >> dx[2] >> rho[2];
instream >> zt[2][1] >> mt[2][1] >> t[2][1];
instream >> n[2];
instream >> dx[3] >> rho[3];
instream >> zt[3][1] >> mt[3][1] >> t[3][1];
instream >> n[3];
for (w = 0; w <= 3; w++)
{ if (n[w] != 1) n[w] = 1; }
instream.close();
Layer = 3;
//done with primary (crude) setup, off to reading scoef.dat file
iz = z1;
getstructScoef(iz, scoefz1, “scoef1.dat”); //used to get pcoef data yy in trim85
//so we put the values in yy here immediately
for (w = 1; w <= 8; w++)
{ yy[w] = scoefz1.pcoef[w]; }
//note: although yy turns out to be just a dummy array
e0 = e0kev*1000; //convert to ev.
if (ed == 0.) ed = 25.0;
ef = Max(5.0, e0kev*0.1);
//alfa = angle of incidence, alpha = radian of alfa
alfa = 0.;
alpha = alfa*Pi/180;
tmin = 5.0;
tau = 0.0;
da = 3.0;
if (iy == 0) iy = 16381;
//now calculate the total depth of each layer = xx(l), and grid spacing cw
xx[1] = dx[1];
for (w = 2; w <= 3; w++) { xx[w] = dx[w] + xx[w-1]; }
if (cw == 0) cw = 0.01*xx[3];
L0 = cw;
//take care of any custom variable or struct I made
rstp.vfermi = 0.0; //set this to 0. for the time being (see log for explanation)
//now, off to avg mass of layer in the next void function
}
//avg mass and atomic number of each layer
void calculateAvgMassOfLayer()
{
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
h[LL] = h[LL] + t[LL][w];
//cout << “testing here..” << rstp.vfermi << endl;
}
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
t[LL][w] = t[LL][w]/h[LL];
m2[LL] = m2[LL] + t[LL][w] * mt[LL][w];
z2[LL] = z2[LL] + t[LL][w] * zt[LL][w];
//note: z2 wont be an integer once t has a value other than 1.0??
//so are we calculating average atomic number here? why?
}
}
//done with this, off to finding electronic stopping powers in the next function
}
void getStoppingForTarget()
{
iz1 = z1; ee = 0;
for (int LL = 1; LL <= Layer; LL++)
{
arho[LL] = rho[LL] * 0.6022/(m2[LL]);
mu[LL] = m1/(m2[LL]);
int ii = n[LL];
for (int nn = 1; nn <= ii; nn++)
{
//set rstp.se[1..1000] = 0. Clear it for the next loop
for (w = 1; w <= 1000; w++)
{ rstp.se[w] = 0.; }
izt = zt[LL][nn];
//calling getrstop now. units, lfctr, vfermi = 1 (doesnt matter)
getrStop(iz1, izt, e0kev, 1, 1., 1., rstp); //rstp defined in header
//set this anyway, though I dont calculate this in RSTOP
vf[LL][nn] = rstp.vfermi; //which is just set 0 in the struct def.
for (w = 1; w <= 1000; w++)
{
se[LL][w] = se[LL][w] + rstp.se[w] * t[LL][nn] * arho[LL];
}
}
}
//now, off to setting up initial conditions next function
}
void setInitialConditions()
{
nh = hn; //number of histories
for (int LL = 1; LL <= Layer; LL++)
{
a[LL] = 0.5292 * 0.8853 / ( pow(z1, 0.23) + pow(z2[LL], 0.23) );
//now calculate the mean flight path with the conditions given in trim85
f[LL] = a[LL] * m2[LL] / ( z1 * z2[LL] * 14.4 * (m1 + m2[LL] ) );
epso = e0 * f[LL];
epsdg[LL] = tmin * f[LL] * pow( (1.0 + mu[LL]) , 2) / (4.0 * mu[LL]);
fd[LL] = 0.01 * pow( z2[LL], (-7.0/3.0) );
kd[LL] = 0.1334 * pow ( z2[LL], (2.0/3.0) ) / sqrt( m2[LL] );
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
my[LL][w] = m1/mt[LL][w];
ec[LL][w] = 4.0 * my[LL][w] / pow( ( 1.0 + my[LL][w] ), 2);
ai[LL][w] = 0.5292 * 0.8853 / ( pow(z1,0.23) + pow(zt[LL][w],0.23) );
fi[LL][w] = ai[LL][w] * mt[LL][w] / ( z1 * zt[LL][w] * 14.4 * ( m1 + mt[LL][w] ) );
}
}
cout << “Setup finished. Starting Monte Carlo Loops..”;
//off to monte carlo loop in next routine
}
void MonteCarlo()
{
//custom variables and arrays for this section
double e;
double cosin = 0.0, siny = 0.0, sine = 0.0, cosy = 0.0;
double pl = 0.0;
int ic;
int LL = 1;
double eps;
double eeg;
double p;
double b;
int ie, ia; //not sure if ie or ia should be double. They are used to access elements
of the m[][] array at some point
double see;
double dee;
double s2, c2, ct, st;
double r, rr;
double ex1, ex2, ex3, ex4;
double v, v1;
double fr, fr1;
double q;
double roc, sqe;
double cc, aa, ff;
double delta, co;
double den;
double phi, psi;
double x1;
int ip;
//variables for crystal calculations
double sep = 0.0;
int ionCounter = 0;
double p1, p2;
double Theta = 0.0;
double rTheta = 0.0, rPhi = 0.0;
double thetaThreshold = 0.5;
double crystalMuonY = 0.0, crystalMuonZ = 0.0;
//amount of translations in y and z axes
double translationY = 0.0, translationZ = 0.0;
//Scatter Plot variables
const int numScatterPlotBins = 5;
double scatterPlot[numScatterPlotBins + 1] = {0.0};
//Vector declarations
//lattice constant of Target (input from file)
double latticeConstant = latticeConst;
Vector3 ions[4];
Vector3 ionsOrdered[4];
Vector3 neighborIonsBCC[14];
Vector3 neighborIonsFCC[14];
Vector3 ionTranslationY(0,translationY,0);
Vector3 ionTranslationZ(0,0,translationZ);
Vector3 unitzplus, unitzminus, unityplus, unityminus, unitxplus, unitxminus;
unitzplus.z = 1;
unitzminus.z = -1;
unityplus.y = 1;
unityminus.y = -1;
unitxplus.x = 1;
unitxminus.x = -1;
Vector3 initialDirection(1,0,0);
Vector3 d;
d.x = 1;
d *= latticeConstant/2;
Vector3 lx(latticeConstant/2, 0, 0);
Vector3 ly(0, latticeConstant/2, 0);
Vector3 lz(0, 0, latticeConstant/2);
Vector3 lambda;
Vector3 lambdaPrime;
Vector3 pVector;
Vector3 pUnitVector;
Vector3 sepVector;
Vector3 Di;
Vector3 DiPrev;
//Vector3 DiPrevToDi;
Vector3 delX;
Vector3 delX1, delX2;
Vector3 dummy1, dummy2, temp;
Vector3 scatterIonPos;
//initialize the random number generator
srand(time(NULL));
//open file to write output
ofstream outStream;
outStream.open(“coords0.txt”);
if(outStream.fail())
{
exitOnError(“Could not open Output file”);
}
//write basic information in the output file
//number of ions, ion energy, total depth, depth of each layer
outStream << nh << “\t” << e0kev << “\t” << xx[Layer] << “\t” << dx[1] << “\t”
<< dx[2] << “\t” << dx[3] << endl;
//open scatter plot file to write current Y and Z coordinates of muons at designated
intervals
ofstream scatterStream;
scatterStream.open(“scatterOut1.txt”);
if(scatterStream.fail())
{
exitOnError(“Could not open Scatter Plot Output file”);
}
//open range distribution file to write final X coordinates of muons
ofstream rangeStream;
rangeStream.open(“rangeOut1.txt”);
if(rangeStream.fail())
{
exitOnError(“Could not open Range Distribution Output file”);
}
//Open general information dump file
ofstream infoStream;
infoStream.open(“info1.txt”);
if(infoStream.fail())
{
exitOnError(“Could not open general information Output file”);
}
//Entering the target
//First set up for the top layer
for (ih = 1; ih <= nh; ih++)
{
avex = xsum / Max(1.0, (float)(ih - ib - it - 1));
if (talk == 2) cout << “Average ion range so far: “ << avex << “ angstroms.”
<<endl;
if (talk > 2) cout << “Now starting ion number “ << ih << endl;
e = e0;
//set scatterPlot array (the intervals)
scatterPlot[0] = 10;
scatterPlot[1] = 30;
scatterPlot[2] = 50;
scatterPlot[3] = 100;
scatterPlot[4] = 150;
scatterPlot[5] = 200;
/*
for(int ccc = 0; ccc <= numScatterPlotBins; ccc++)
{
cout << “scatter plot “ << ccc << “: “ << scatterPlot[ccc] << endl;
}
*/
//Initial Ion Positions
ions[0] = d + ionTranslationZ + unitzminus * (latticeConstant/2);
ions[1] = d + ionTranslationZ + unitzplus * (latticeConstant/2);
ions[2] = d * 2 + ionTranslationY + unityminus * (latticeConstant/2);
ions[3] = d * 2 + ionTranslationY + unityplus * (latticeConstant/2);
//Create a polygon that resides on the lateral axes.
//The points are put on anticlockwise order, which is important for
//testing whether the test point lies on this polygon
ionsOrdered[0] = ions[0];
ionsOrdered[1] = ions[2];
ionsOrdered[2] = ions[1];
ionsOrdered[3] = ions[3];
//generate random theta and phi angles.
rTheta = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * thetaThreshold;
rPhi = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * 2 * Pi;
//find corresponding x, y and z components of the direction vector.
//radius of the direction vector is 1
initialDirection.x = cos(rTheta);
initialDirection.z = sin(rTheta) * cos(rPhi);
initialDirection.y = sin(rTheta) * sin(rPhi);
//set the counter to 0 for a new ion
ionCounter = 0;
pl = 0.0;
ic = 0;
//set initial DiPrev - the origin
DiPrev.x = 0.0; DiPrev.y = 0.0; DiPrev.z = 0.0;
//set initial lambda, the direction of motion. Normalize it.
lambda.clear();
lambda = initialDirection;
lambda.normalize();
//set initial delX to origin
delX.clear();
//clear the dummy delX vectors, set them to origin
delX1.clear();
delX2.clear();
dummy1.clear();
dummy2.clear();
temp.clear();
LL = 1;
//set transmitted and backscattered to false
transmitted = 0;
backscattered = 0;
//set channeling to true
insideChannel = 1;
neighborFlag = 0;
//write the initial coordinates to the output file
outStream << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << endl << “Initial: “;
//cout << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << “r1 = “ << r1 << endl;
//cycle for each collision until the energy of the particle becomes too low, or
the particle backscatters, or it goes out of the last layer (transmission)
//needs a do while loop here,
//which I will mention as the ‘mother loop’ from now.
do
{
ic = ic + 1;
eps = e * f[LL];
eeg = sqrt(eps*epsdg[LL]);
//pmax[LL] = a[LL] / (eeg + sqrt(eeg) + 0.125 * pow( eeg, 0.1) );
pmax[LL] = sqrt(3) * (latticeConstant / 2) * 0.7;
//Calculate impact parameter and choose the atom to scatter from.
//Do this for ion pairs 0,1 and 2,3.
if (ionCounter == 0)
{
delX1 = ions[0] - DiPrev;
delX2 = ions[1] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[0];
ions[0] = ions[1];
ions[1] = temp;
//cout << “Vertical Ions swapped” << endl;
}
}
if (ionCounter == 2)
{
delX1 = ions[2] - DiPrev;
delX2 = ions[3] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[2];
ions[2] = ions[3];
ions[3] = temp;
//cout << “Horizontal Ions swapped” << endl;
}
}
//now calculate impact parameter
if(neighborFlag == 0)
{
delX = ions[ionCounter] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
else if(neighborFlag == 1)
{
double impact[13] = {0.0};
double radial[13] = {0.0};
double S[13] = {0.0};
double sumS = 0.0;
double Probability[13] = {0.0};
double rnd_candidate = 0.0;
int selected_candidate = -1;
for(int ncount = 0; ncount <= 13; ncount++)
{
delX = neighborIonsBCC[ncount] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
//scatterIonPos = neighborIonsBCC[ncount];
impact[ncount] = p;
radial[ncount] = delX.magnitude();
S[ncount] = 1 / ( pow(impact[ncount],2) * radial[ncount] );
sumS += S[ncount];
//general scheme of selecting the neighbor ion
// if(p < pmax[LL])
// {
// scatterIonPos = neighborIonsBCC[ncount];
// //cout << “Neighbor “ << ncount << “ is selected” << endl;
// break;
// }
}
for(int ncount = 0; ncount <= 13; ncount++)
{
Probability[ncount] = S[ncount] / sumS;
}
//print out the probability array
cout << endl;
for(int ncount = 0; ncount <= 13; ncount++)
{
//cout << Probability[ncount] << “ “;
infoStream << Probability[ncount] << “ “;
}
infoStream << endl;
//cout << endl;
//random number between 0 and 1
rnd_candidate = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) );
//cout << “rand_candidate: “ << rnd_candidate << endl;
//choose the candidate for scattering
selected_candidate = whichNonUniformBin(rnd_candidate, Probability, 13);
//cout << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate <<
endl;
infoStream << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate
<< endl;
//assign the scatterIonPos variable to the selected neighbor
scatterIonPos = neighborIonsBCC[selected_candidate];
//cout << “Scattering Ion Position: “; scatterIonPos.printVector();
//find the essential quantities for the selected neighbor
delX = neighborIonsBCC[selected_candidate] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
//find eps and b using fi[LL][nn], using nn that I was supposed to find from above
//here im deliberately using nn = 1
eps = fi[LL][1] * e;
b = p / ai[LL][1];
if (eps > 10) //rutherford scattering
{
s2 = 1.0 / (1.0 + (1.0 + b * (1.0 + b)) * pow((2.0 * eps * b), 2) );
c2 = 1.0 - s2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
else //magic formula
{
r = b;
rr = -2.7 * log(eps * b);
if (rr >= b)//note >= sign instead < in trim85
{
rr = -2.7 * log(eps * rr);
if (rr >= b)//note >= sign instead < in trim85
{
r = rr;
}
}
//do while loop that replaces line 330 loop
do
{
ex1 = 0.18175 * exp(-3.1998 * r);
ex2 = 0.50986 * exp(-0.94229 * r);
ex3 = 0.28022 * exp(-0.4029 * r);
ex4 = 0.028171 * exp(-0.20162 * r);
v = (ex1 + ex2 + ex3 + ex4) / r;
v1 = -(v + 3.1998 * ex1 + 0.94229 * ex2 + 0.4029 * ex3 + 0.20162 * ex4) / r;
fr = b * b / r + v * r / eps - r;
fr1 = -b * b / (r * r) + (v + v1 * r) / eps - 1.0;
q = fr / fr1;
r = r - q;
}
while( (Abs(q / r)) > 0.001 );
roc = -2.0 * (eps - v) / v1;
sqe = sqrt(eps);
//5 parameter magic scattering calculation
//below is for universal potential
cc = (0.011615 + sqe) / (0.0071222 + sqe);
aa = 2.0 * eps * (1.0 + (0.99229 / sqe) ) * ( pow(b, cc) );
ff = ( sqrt(aa * aa + 1.0) - aa) * ( (9.3066 + eps) / (14.813 + eps) );
delta = (r - b) * aa * ff / (ff + 1.0);
co = (b + delta + roc) / (r + roc);
c2 = co * co;
s2 = 1.0 - c2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
Theta = acos(ct);
//we are done finding theta (in CM system). So calculate all other quantities.
//find separation and the separation vector.
phi = (Pi - Theta) / 2;
sep = p / tan(phi);
sepVector = lambda * sep;
//find theta in laboratory frame - psi
psi = atan(st / (ct + my[LL][1] ) );
//note: change my[LL][1] to my[LL][nn] when the above section is fixed.
if (psi < 0 ) psi = psi + Pi; //should I do this for crystals?
//find Di, the scattering point vector
Di = DiPrev + delX + pVector - sepVector;
//find new direction of motion
lambdaPrime = lambda * cos(psi) + pUnitVector * sin(psi);
lambdaPrime.normalize();
//find length of step, ls = distance of Di from DiPrev
ls = Di.getDistance(DiPrev);
//find energy lost due to electronic stopping, dee
ie = (int)(e/e0kev+0.5); //should it be 0.5? or less so that ie <=1000?
see = se[LL][ie];
if (e < e0kev) see = se[LL][1] * sqrt(e/e0kev);
dee = ls * see;
// den = energy transferred to recoil
den = ec[LL][1] * s2 * e; //note: I am using ec[LL][1] here instead of [LL][nn].
//cout << “den = “ << den << “, dee = “ << dee << endl;
infoStream << “den = “ << den << “, dee = “ << dee << endl;
e = e - den - dee;
//cout << endl<< “current ion energy: “ << e << endl;
if (dee > maximum) maximum = dee;
pl = pl + ls - tau;
//write the ion position to output file
outStream << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
if((ic%30)==0)
{
//cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
}
//determine which scatter plot Di’s x value belongs to.
//output the y and z coordinates to scatter plot file accordingly.
for(int cc = 0; cc <= numScatterPlotBins; cc++)
{
if( Di.x >= (scatterPlot[cc]) )
{
crystalMuonY = Di.y - translationY;
crystalMuonZ = Di.z - translationZ;
//cout << “scatter plot “ << ct << “: “ << scatterPlot[ct] << endl;
scatterStream << scatterPlot[cc] << “\t” << crystalMuonY << “\t” <<
crystalMuonZ << endl;
//set scatterPlot[ss] to a big number
scatterPlot[cc] = 10000;
//break out of this for loop
break;
}
}
//determine if Di is in the channeling region.
//insideChannel = Di.isInsidePolygon(ionsOrdered, 4);
//break out of parent loop if not inside the channel
if(insideChannel == 0)
{
cout << “Ion “ << ih << “ is out of Channel” << endl;
cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
break;
}
//determine which layer the next collision will be in
if (Di.x < 0.0) //particle is backscattered
{
backscattered = 1; //cout << “ion number “ << ih << “ backscattered.” << endl;
infoStream << “ion number “ << ih << “ backscattered.” << endl;
ib = ib + 1;
eb = eb + e;
break; //break out of ‘mother do loop’ and continue with the next session of
for loop.
}
//here we set the current or next layer the particle will be in
for (w = 1; w <= Layer; w++)
{
if ( (Di.x <= xx[w]) && (w == 1) )
{
LL = 1;
//cout << endl<<”ion is in layer “ << LL << endl;
break;
//break out of this For loop and go check if the particle is transmitted.
}
else if ( (Di.x <= xx[w]) && (Di.x > xx[w-1]) )
{
LL = w;
//cout << “ion is in layer “ << LL <<endl;
break; //break out of this For loop and go check if the particle is
transmitted.
}
}
//now, check for particle transmission, i.e. whether the particle went out of the
last layer.
if(Di.x >= xx[Layer])
{
//particle is transmitted, take care of appropriate variables and break
transmitted = 1;//cout << “ion number “ << ih << “ transmitted.” << endl;
it = it + 1;
et = et + e;
ia = 57.295779 * acos(cosin) / da + 1.0;
ie = 100 * e / e0 + 1.0;
//m[ie][ia] = m[ie][ia] + 1;//note: how is this possible? ie and ia should be
integers in order to access the elements of the array m[][]. But we calculate them as
doubles here!
break; //break out of the ‘mother’ do loop
}
//now take care of ionCounter and other variables for the next scattering
if(neighborFlag == 0)
{
if(ionCounter == 3)
{
//ionCounter = 0;
neighborFlag = 1;
scatterIonPos = ions[3];
//cout << endl << “got out of first two layers” << endl;
}
else
{
ionCounter++;
}
}
if(neighborFlag == 1)
{
//cout << “Updating Neighbor Ions” << endl;
neighborIonsBCC[0] = scatterIonPos + lx - ly + lz;
neighborIonsBCC[1] = scatterIonPos + lx + ly + lz;
neighborIonsBCC[2] = scatterIonPos + lx + ly - lz;
neighborIonsBCC[3] = scatterIonPos + lx - ly - lz;
neighborIonsBCC[4] = scatterIonPos + lx * 2;
neighborIonsBCC[5] = scatterIonPos - lx - ly - lz;
neighborIonsBCC[6] = scatterIonPos - lx + ly - lz;
neighborIonsBCC[7] = scatterIonPos - lx + ly + lz;
neighborIonsBCC[8] = scatterIonPos - lx - ly + lz;
neighborIonsBCC[9] = scatterIonPos + lz * 2;
neighborIonsBCC[10] = scatterIonPos - lz * 2;
neighborIonsBCC[11] = scatterIonPos + ly * 2;
neighborIonsBCC[12] = scatterIonPos - ly * 2;
neighborIonsBCC[13] = scatterIonPos - lx * 2;
}
//set DiPrev to Di
DiPrev = Di;
//update current lambda to lambdaPrime
lambda = lambdaPrime;
//now the while condition of the mother do loop checks if the particle has lesser
energy than our lowest energy limit, ef.
}
while(e > ef);
//since we are out of the mother do loop now, the particle must have come to a
stop. So, increase the final particle distributions if the particle has not been
transmitted or backscattered.
if( ((transmitted == 0)) && ((backscattered == 0)) && ((insideChannel == 1)) )
{
ip = (int)(pl/cw + 1.0);
if(ip > 100) ip = 100;
//ipl[ip] = ipl[ip] + 1;
xsum = xsum + Di.x;
//my own bin function
selectedXBin = whichBin(Di.x, xx[Layer], numXBin);
//write the selected bin to the output file
//outStream << selectedXBin << endl;
//cout << x << endl << xx[Layer] << endl << numXBin << endl << selectedXBin;
xBin[selectedXBin] = xBin[selectedXBin] + 1;
//print final x value for plotting histogram
//cout << “ion “ << ih << “ final x: “ << Di.x << endl;
infoStream << “ion “ << ih << “ final x: “ << Di.x << endl;
//cout << Di.x << “,”;
rangeStream << Di.x << endl;
plsum = plsum + pl;
icsum = icsum + ic;
//ipl is the ion path length - the total avg. distance the ion travels
regardless of direction before it comes to stop
}
//that brings us to the end of one ion’s journey, now go to next ion by going back
to the for loop’s beginning..
}
//and this ends the monte carlo loop function. Take care of necessary structures and
variables that need to be cleared/deleted
outStream.close();
scatterStream.close();
infoStream << “Number of Backscattered Ions: “ << ib << endl;
infoStream.close();
rangeStream.close();
}
int whichNonUniformBin(double e, double arr[], int numBins)
{
double low = 0, high = arr[0];
if((e>=low) && (e<high))
return 0;
else
{
for(int i = 0; i < numBins; i++)
{
low += arr[i];
high += arr[i+1];
//cout << “\tlow: “ << low << “, high:” << high << endl;
if((e>=low) && (e<high))
return i;
}
}
}
128
//============================================================================
// Name : monte.cpp
// Author : Nazmus Saquib
// Version :
// Copyright :
// Description : BCA code in C++
//============================================================================
#include “Globals.h”
#include “scoef.h”
#include “rstop.h”
#include “muscle_bca.h”
#include “vectorGeometry.h”
const int numXBin = 100;
const int numIons = 1;
int xBin[numXBin+1] = {0};
int selectedXBin = 0;
double rho[4]={0.0};
int n[]={0,0,0,0};
double e0kev, m1, cw, ed, latticeConst;
int z1, hn, iy, nowout;
double dx[3] = {0.0};
int zt[3][7] = {0};
double mt[3][7] = {0.};
double t[3][7] = {0.};
int Layer; //use this for number of layers rather than the L in the program;
//remember this cannot be set to 0. Other loops/arrays may start from
//0, but keep this >= 1;
//the arrays..
double my[3][7]= {0},
ai[3][7]= {0},
fi[3][7]= {0},
ec[3][7]= {0},
io[3][7]= {0},
k[3]= {0},
kl[3][7]= {0};
double vf[3][7]= {0},
mu[3]= {0},
ioniz[3]= {0},
h[3]= {0},
xx[3]= {0},
m2[3]= {0.0},
z2[3]= {0},
c[3]= {0},
epsbk[3]= {0},
arho[3]= {0};
double a[3]= {0},
f[3]= {0},
lm[3]= {0},
pmax[3]= {0},
fd[3]= {0},
kd[3]= {0},
sbk[3]= {0},
lf[3]= {0},
yy[8]= {0};
double se[3][1000]= {0.0},
seo[1000]= {0.0},
epsdg[3]= {0.0};
double ls = 0., lo = 0., maximum = 0.;
double xsum = 0, x2sum = 0, x3sum = 0, x4sum = 0, plsum = 0, pl2sum = 0;
double avex = 0, vari = 0, sigma = 0, v = 0, v2 = 0, Gamma = 0, beta = 0, y = 0, avepl
= 0, sigpl = 0, avecol = 0;
int i = 0, j = 0;
int ib = 0, it = 0;
double eb = 0.0, et = 0.0;
int icsum = 0;
double y2sum = 0, xy2sum = 0, x2y2su = 0, y4sum = 0;
double tau = 0;
int iii = -1;
//my dummy vars
int w; double q;
//my customized data structures or vars
scoefData scoefz1;
rstopData rstp;
//these vars (continuing from this line) are added later as needed, vars that were not
declared in the initialization of trim85 but showed up in the middle.
double e0, ef;
int iz;
double alfa, alpha;
double tmin, da;
double L0;
int iz1;
double ee;
int izt;
double nh;
double epso;
int ih;
double e;
//boolean for keeping track of a particle being transmitted or backscattered
int transmitted = 0;
int backscattered = 0;
//boolean for keeping track of channeling
int insideChannel = 1;
//boolean for determining whether to scatter from neighbor atoms
int neighborFlag = 0;
//main function
int main()
{
cout << “Initializing” << endl;
Initialize(“IronInput.dat”);
calculateAvgMassOfLayer();
getStoppingForTarget();
setInitialConditions();
MonteCarlo();
/* *********************** Testing Ground for arrays and variables
******************** */
for (w = 1; w <= 8; w++) cout << “\t “ << yy[w];
for (w = 1; w <= 3; w++) cout << “\n\t “ << xx[w];
cout << “CW or L0: “ << L0;
//(trouble! The values of n[] elements are changing like crazy)
cout << endl << n[0] << “\t” << n[1] << “\t” << n[2] << “\t” << n[3] << endl;
cout << endl << rho[0] << “\t” << rho[1] << “\t” << rho[2] << “\t” << rho[3] <<
“\t” << rho[4] << endl;
//test z2[], m2[] arrays
for (w = 1; w <= Layer; w++) cout << “\t “ << z2[w];
for (w = 1; w <= Layer; w++) cout << “\n\t “ << m2[w];
//test the se values
cout << endl << se[1][1000] << “ “ << se[2][1000] << “ “ << se[3][1000] << endl;
//test the se[] values by printing 10th element from the array (to be implemented)
//for (w = 1; w <= 100; w++)
//{
//for (int sss = 1; sss <= 50; sss++)
//{
//cout << “\t” << mpart[w][sss];
//}
//}
/* *********************** End of Testing Ground ************************** */
cout << endl;
//Now print values of each bin in xBin
//for (w = 1; w <= numXBin; w++) cout << xBin[w] << “,”;
//print final x values
cout << endl;
cout << “Number of Backscattered Ions: “ << ib << endl;
cout << “Number of Transmitted Ions: “ << it << endl;
return 0;
}
//end of main
//Helper functions follow from here
//initialize variables and setup each layer over here
void Initialize(char* filename)
{
//Read command file
ifstream instream;
instream.open(filename,ios::in);
cout << filename;
if (!instream)
{
exitOnError(filename);
}
instream >> e0kev >> z1 >> m1 >> latticeConst >> hn >> cw >> ed >> iy >> nowout;
instream >> dx[1] >> rho[1];
instream >> zt[1][1] >> mt[1][1] >> t[1][1];
instream >> n[1];
instream >> dx[2] >> rho[2];
instream >> zt[2][1] >> mt[2][1] >> t[2][1];
instream >> n[2];
instream >> dx[3] >> rho[3];
instream >> zt[3][1] >> mt[3][1] >> t[3][1];
instream >> n[3];
for (w = 0; w <= 3; w++)
{ if (n[w] != 1) n[w] = 1; }
instream.close();
Layer = 3;
//done with primary (crude) setup, off to reading scoef.dat file
iz = z1;
getstructScoef(iz, scoefz1, “scoef1.dat”); //used to get pcoef data yy in trim85
//so we put the values in yy here immediately
for (w = 1; w <= 8; w++)
{ yy[w] = scoefz1.pcoef[w]; }
//note: although yy turns out to be just a dummy array
e0 = e0kev*1000; //convert to ev.
if (ed == 0.) ed = 25.0;
ef = Max(5.0, e0kev*0.1);
//alfa = angle of incidence, alpha = radian of alfa
alfa = 0.;
alpha = alfa*Pi/180;
tmin = 5.0;
tau = 0.0;
da = 3.0;
if (iy == 0) iy = 16381;
//now calculate the total depth of each layer = xx(l), and grid spacing cw
xx[1] = dx[1];
for (w = 2; w <= 3; w++) { xx[w] = dx[w] + xx[w-1]; }
if (cw == 0) cw = 0.01*xx[3];
L0 = cw;
//take care of any custom variable or struct I made
rstp.vfermi = 0.0; //set this to 0. for the time being (see log for explanation)
//now, off to avg mass of layer in the next void function
}
//avg mass and atomic number of each layer
void calculateAvgMassOfLayer()
{
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
h[LL] = h[LL] + t[LL][w];
//cout << “testing here..” << rstp.vfermi << endl;
}
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
t[LL][w] = t[LL][w]/h[LL];
m2[LL] = m2[LL] + t[LL][w] * mt[LL][w];
z2[LL] = z2[LL] + t[LL][w] * zt[LL][w];
//note: z2 wont be an integer once t has a value other than 1.0??
//so are we calculating average atomic number here? why?
}
}
//done with this, off to finding electronic stopping powers in the next function
}
void getStoppingForTarget()
{
iz1 = z1; ee = 0;
for (int LL = 1; LL <= Layer; LL++)
{
arho[LL] = rho[LL] * 0.6022/(m2[LL]);
mu[LL] = m1/(m2[LL]);
int ii = n[LL];
for (int nn = 1; nn <= ii; nn++)
{
//set rstp.se[1..1000] = 0. Clear it for the next loop
for (w = 1; w <= 1000; w++)
{ rstp.se[w] = 0.; }
izt = zt[LL][nn];
//calling getrstop now. units, lfctr, vfermi = 1 (doesnt matter)
getrStop(iz1, izt, e0kev, 1, 1., 1., rstp); //rstp defined in header
//set this anyway, though I dont calculate this in RSTOP
vf[LL][nn] = rstp.vfermi; //which is just set 0 in the struct def.
for (w = 1; w <= 1000; w++)
{
se[LL][w] = se[LL][w] + rstp.se[w] * t[LL][nn] * arho[LL];
}
}
}
//now, off to setting up initial conditions next function
}
void setInitialConditions()
{
nh = hn; //number of histories
for (int LL = 1; LL <= Layer; LL++)
{
a[LL] = 0.5292 * 0.8853 / ( pow(z1, 0.23) + pow(z2[LL], 0.23) );
//now calculate the mean flight path with the conditions given in trim85
f[LL] = a[LL] * m2[LL] / ( z1 * z2[LL] * 14.4 * (m1 + m2[LL] ) );
epso = e0 * f[LL];
epsdg[LL] = tmin * f[LL] * pow( (1.0 + mu[LL]) , 2) / (4.0 * mu[LL]);
fd[LL] = 0.01 * pow( z2[LL], (-7.0/3.0) );
kd[LL] = 0.1334 * pow ( z2[LL], (2.0/3.0) ) / sqrt( m2[LL] );
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
my[LL][w] = m1/mt[LL][w];
ec[LL][w] = 4.0 * my[LL][w] / pow( ( 1.0 + my[LL][w] ), 2);
ai[LL][w] = 0.5292 * 0.8853 / ( pow(z1,0.23) + pow(zt[LL][w],0.23) );
fi[LL][w] = ai[LL][w] * mt[LL][w] / ( z1 * zt[LL][w] * 14.4 * ( m1 + mt[LL][w] ) );
}
}
cout << “Setup finished. Starting Monte Carlo Loops..”;
//off to monte carlo loop in next routine
}
void MonteCarlo()
{
//custom variables and arrays for this section
double e;
double cosin = 0.0, siny = 0.0, sine = 0.0, cosy = 0.0;
double pl = 0.0;
int ic;
int LL = 1;
double eps;
double eeg;
double p;
double b;
int ie, ia; //not sure if ie or ia should be double. They are used to access elements
of the m[][] array at some point
double see;
double dee;
double s2, c2, ct, st;
double r, rr;
double ex1, ex2, ex3, ex4;
double v, v1;
double fr, fr1;
double q;
double roc, sqe;
double cc, aa, ff;
double delta, co;
double den;
double phi, psi;
double x1;
int ip;
//variables for crystal calculations
double sep = 0.0;
int ionCounter = 0;
double p1, p2;
double Theta = 0.0;
double rTheta = 0.0, rPhi = 0.0;
double thetaThreshold = 0.5;
double crystalMuonY = 0.0, crystalMuonZ = 0.0;
//amount of translations in y and z axes
double translationY = 0.0, translationZ = 0.0;
//Scatter Plot variables
const int numScatterPlotBins = 5;
double scatterPlot[numScatterPlotBins + 1] = {0.0};
//Vector declarations
//lattice constant of Target (input from file)
double latticeConstant = latticeConst;
Vector3 ions[4];
Vector3 ionsOrdered[4];
Vector3 neighborIonsBCC[14];
Vector3 neighborIonsFCC[14];
Vector3 ionTranslationY(0,translationY,0);
Vector3 ionTranslationZ(0,0,translationZ);
Vector3 unitzplus, unitzminus, unityplus, unityminus, unitxplus, unitxminus;
unitzplus.z = 1;
unitzminus.z = -1;
unityplus.y = 1;
unityminus.y = -1;
unitxplus.x = 1;
unitxminus.x = -1;
Vector3 initialDirection(1,0,0);
Vector3 d;
d.x = 1;
d *= latticeConstant/2;
Vector3 lx(latticeConstant/2, 0, 0);
Vector3 ly(0, latticeConstant/2, 0);
Vector3 lz(0, 0, latticeConstant/2);
Vector3 lambda;
Vector3 lambdaPrime;
Vector3 pVector;
Vector3 pUnitVector;
Vector3 sepVector;
Vector3 Di;
Vector3 DiPrev;
//Vector3 DiPrevToDi;
Vector3 delX;
Vector3 delX1, delX2;
Vector3 dummy1, dummy2, temp;
Vector3 scatterIonPos;
//initialize the random number generator
srand(time(NULL));
//open file to write output
ofstream outStream;
outStream.open(“coords0.txt”);
if(outStream.fail())
{
exitOnError(“Could not open Output file”);
}
//write basic information in the output file
//number of ions, ion energy, total depth, depth of each layer
outStream << nh << “\t” << e0kev << “\t” << xx[Layer] << “\t” << dx[1] << “\t”
<< dx[2] << “\t” << dx[3] << endl;
//open scatter plot file to write current Y and Z coordinates of muons at designated
intervals
ofstream scatterStream;
scatterStream.open(“scatterOut1.txt”);
if(scatterStream.fail())
{
exitOnError(“Could not open Scatter Plot Output file”);
}
//open range distribution file to write final X coordinates of muons
ofstream rangeStream;
rangeStream.open(“rangeOut1.txt”);
if(rangeStream.fail())
{
exitOnError(“Could not open Range Distribution Output file”);
}
//Open general information dump file
ofstream infoStream;
infoStream.open(“info1.txt”);
if(infoStream.fail())
{
exitOnError(“Could not open general information Output file”);
}
//Entering the target
//First set up for the top layer
for (ih = 1; ih <= nh; ih++)
{
avex = xsum / Max(1.0, (float)(ih - ib - it - 1));
if (talk == 2) cout << “Average ion range so far: “ << avex << “ angstroms.”
<<endl;
if (talk > 2) cout << “Now starting ion number “ << ih << endl;
e = e0;
//set scatterPlot array (the intervals)
scatterPlot[0] = 10;
scatterPlot[1] = 30;
scatterPlot[2] = 50;
scatterPlot[3] = 100;
scatterPlot[4] = 150;
scatterPlot[5] = 200;
/*
for(int ccc = 0; ccc <= numScatterPlotBins; ccc++)
{
cout << “scatter plot “ << ccc << “: “ << scatterPlot[ccc] << endl;
}
*/
//Initial Ion Positions
ions[0] = d + ionTranslationZ + unitzminus * (latticeConstant/2);
ions[1] = d + ionTranslationZ + unitzplus * (latticeConstant/2);
ions[2] = d * 2 + ionTranslationY + unityminus * (latticeConstant/2);
ions[3] = d * 2 + ionTranslationY + unityplus * (latticeConstant/2);
//Create a polygon that resides on the lateral axes.
//The points are put on anticlockwise order, which is important for
//testing whether the test point lies on this polygon
ionsOrdered[0] = ions[0];
ionsOrdered[1] = ions[2];
ionsOrdered[2] = ions[1];
ionsOrdered[3] = ions[3];
//generate random theta and phi angles.
rTheta = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * thetaThreshold;
rPhi = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * 2 * Pi;
//find corresponding x, y and z components of the direction vector.
//radius of the direction vector is 1
initialDirection.x = cos(rTheta);
initialDirection.z = sin(rTheta) * cos(rPhi);
initialDirection.y = sin(rTheta) * sin(rPhi);
//set the counter to 0 for a new ion
ionCounter = 0;
pl = 0.0;
ic = 0;
//set initial DiPrev - the origin
DiPrev.x = 0.0; DiPrev.y = 0.0; DiPrev.z = 0.0;
//set initial lambda, the direction of motion. Normalize it.
lambda.clear();
lambda = initialDirection;
lambda.normalize();
//set initial delX to origin
delX.clear();
//clear the dummy delX vectors, set them to origin
delX1.clear();
delX2.clear();
dummy1.clear();
dummy2.clear();
temp.clear();
LL = 1;
//set transmitted and backscattered to false
transmitted = 0;
backscattered = 0;
//set channeling to true
insideChannel = 1;
neighborFlag = 0;
//write the initial coordinates to the output file
outStream << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << endl << “Initial: “;
//cout << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << “r1 = “ << r1 << endl;
//cycle for each collision until the energy of the particle becomes too low, or
the particle backscatters, or it goes out of the last layer (transmission)
//needs a do while loop here,
//which I will mention as the ‘mother loop’ from now.
do
{
ic = ic + 1;
eps = e * f[LL];
eeg = sqrt(eps*epsdg[LL]);
//pmax[LL] = a[LL] / (eeg + sqrt(eeg) + 0.125 * pow( eeg, 0.1) );
pmax[LL] = sqrt(3) * (latticeConstant / 2) * 0.7;
//Calculate impact parameter and choose the atom to scatter from.
//Do this for ion pairs 0,1 and 2,3.
if (ionCounter == 0)
{
delX1 = ions[0] - DiPrev;
delX2 = ions[1] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[0];
ions[0] = ions[1];
ions[1] = temp;
//cout << “Vertical Ions swapped” << endl;
}
}
if (ionCounter == 2)
{
delX1 = ions[2] - DiPrev;
delX2 = ions[3] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[2];
ions[2] = ions[3];
ions[3] = temp;
//cout << “Horizontal Ions swapped” << endl;
}
}
//now calculate impact parameter
if(neighborFlag == 0)
{
delX = ions[ionCounter] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
else if(neighborFlag == 1)
{
double impact[13] = {0.0};
double radial[13] = {0.0};
double S[13] = {0.0};
double sumS = 0.0;
double Probability[13] = {0.0};
double rnd_candidate = 0.0;
int selected_candidate = -1;
for(int ncount = 0; ncount <= 13; ncount++)
{
delX = neighborIonsBCC[ncount] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
//scatterIonPos = neighborIonsBCC[ncount];
impact[ncount] = p;
radial[ncount] = delX.magnitude();
S[ncount] = 1 / ( pow(impact[ncount],2) * radial[ncount] );
sumS += S[ncount];
//general scheme of selecting the neighbor ion
// if(p < pmax[LL])
// {
// scatterIonPos = neighborIonsBCC[ncount];
// //cout << “Neighbor “ << ncount << “ is selected” << endl;
// break;
// }
}
for(int ncount = 0; ncount <= 13; ncount++)
{
Probability[ncount] = S[ncount] / sumS;
}
//print out the probability array
cout << endl;
for(int ncount = 0; ncount <= 13; ncount++)
{
//cout << Probability[ncount] << “ “;
infoStream << Probability[ncount] << “ “;
}
infoStream << endl;
//cout << endl;
//random number between 0 and 1
rnd_candidate = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) );
//cout << “rand_candidate: “ << rnd_candidate << endl;
//choose the candidate for scattering
selected_candidate = whichNonUniformBin(rnd_candidate, Probability, 13);
//cout << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate <<
endl;
infoStream << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate
<< endl;
//assign the scatterIonPos variable to the selected neighbor
scatterIonPos = neighborIonsBCC[selected_candidate];
//cout << “Scattering Ion Position: “; scatterIonPos.printVector();
//find the essential quantities for the selected neighbor
delX = neighborIonsBCC[selected_candidate] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
//find eps and b using fi[LL][nn], using nn that I was supposed to find from above
//here im deliberately using nn = 1
eps = fi[LL][1] * e;
b = p / ai[LL][1];
if (eps > 10) //rutherford scattering
{
s2 = 1.0 / (1.0 + (1.0 + b * (1.0 + b)) * pow((2.0 * eps * b), 2) );
c2 = 1.0 - s2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
else //magic formula
{
r = b;
rr = -2.7 * log(eps * b);
if (rr >= b)//note >= sign instead < in trim85
{
rr = -2.7 * log(eps * rr);
if (rr >= b)//note >= sign instead < in trim85
{
r = rr;
}
}
//do while loop that replaces line 330 loop
do
{
ex1 = 0.18175 * exp(-3.1998 * r);
ex2 = 0.50986 * exp(-0.94229 * r);
ex3 = 0.28022 * exp(-0.4029 * r);
ex4 = 0.028171 * exp(-0.20162 * r);
v = (ex1 + ex2 + ex3 + ex4) / r;
v1 = -(v + 3.1998 * ex1 + 0.94229 * ex2 + 0.4029 * ex3 + 0.20162 * ex4) / r;
fr = b * b / r + v * r / eps - r;
fr1 = -b * b / (r * r) + (v + v1 * r) / eps - 1.0;
q = fr / fr1;
r = r - q;
}
while( (Abs(q / r)) > 0.001 );
roc = -2.0 * (eps - v) / v1;
sqe = sqrt(eps);
//5 parameter magic scattering calculation
//below is for universal potential
cc = (0.011615 + sqe) / (0.0071222 + sqe);
aa = 2.0 * eps * (1.0 + (0.99229 / sqe) ) * ( pow(b, cc) );
ff = ( sqrt(aa * aa + 1.0) - aa) * ( (9.3066 + eps) / (14.813 + eps) );
delta = (r - b) * aa * ff / (ff + 1.0);
co = (b + delta + roc) / (r + roc);
c2 = co * co;
s2 = 1.0 - c2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
Theta = acos(ct);
//we are done finding theta (in CM system). So calculate all other quantities.
//find separation and the separation vector.
phi = (Pi - Theta) / 2;
sep = p / tan(phi);
sepVector = lambda * sep;
//find theta in laboratory frame - psi
psi = atan(st / (ct + my[LL][1] ) );
//note: change my[LL][1] to my[LL][nn] when the above section is fixed.
if (psi < 0 ) psi = psi + Pi; //should I do this for crystals?
//find Di, the scattering point vector
Di = DiPrev + delX + pVector - sepVector;
//find new direction of motion
lambdaPrime = lambda * cos(psi) + pUnitVector * sin(psi);
lambdaPrime.normalize();
//find length of step, ls = distance of Di from DiPrev
ls = Di.getDistance(DiPrev);
//find energy lost due to electronic stopping, dee
ie = (int)(e/e0kev+0.5); //should it be 0.5? or less so that ie <=1000?
see = se[LL][ie];
if (e < e0kev) see = se[LL][1] * sqrt(e/e0kev);
dee = ls * see;
// den = energy transferred to recoil
den = ec[LL][1] * s2 * e; //note: I am using ec[LL][1] here instead of [LL][nn].
//cout << “den = “ << den << “, dee = “ << dee << endl;
infoStream << “den = “ << den << “, dee = “ << dee << endl;
e = e - den - dee;
//cout << endl<< “current ion energy: “ << e << endl;
if (dee > maximum) maximum = dee;
pl = pl + ls - tau;
//write the ion position to output file
outStream << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
if((ic%30)==0)
{
//cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
}
//determine which scatter plot Di’s x value belongs to.
//output the y and z coordinates to scatter plot file accordingly.
for(int cc = 0; cc <= numScatterPlotBins; cc++)
{
if( Di.x >= (scatterPlot[cc]) )
{
crystalMuonY = Di.y - translationY;
crystalMuonZ = Di.z - translationZ;
//cout << “scatter plot “ << ct << “: “ << scatterPlot[ct] << endl;
scatterStream << scatterPlot[cc] << “\t” << crystalMuonY << “\t” <<
crystalMuonZ << endl;
//set scatterPlot[ss] to a big number
scatterPlot[cc] = 10000;
//break out of this for loop
break;
}
}
//determine if Di is in the channeling region.
//insideChannel = Di.isInsidePolygon(ionsOrdered, 4);
//break out of parent loop if not inside the channel
if(insideChannel == 0)
{
cout << “Ion “ << ih << “ is out of Channel” << endl;
cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
break;
}
//determine which layer the next collision will be in
if (Di.x < 0.0) //particle is backscattered
{
backscattered = 1; //cout << “ion number “ << ih << “ backscattered.” << endl;
infoStream << “ion number “ << ih << “ backscattered.” << endl;
ib = ib + 1;
eb = eb + e;
break; //break out of ‘mother do loop’ and continue with the next session of
for loop.
}
//here we set the current or next layer the particle will be in
for (w = 1; w <= Layer; w++)
{
if ( (Di.x <= xx[w]) && (w == 1) )
{
LL = 1;
//cout << endl<<”ion is in layer “ << LL << endl;
break;
//break out of this For loop and go check if the particle is transmitted.
}
else if ( (Di.x <= xx[w]) && (Di.x > xx[w-1]) )
{
LL = w;
//cout << “ion is in layer “ << LL <<endl;
break; //break out of this For loop and go check if the particle is
transmitted.
}
}
//now, check for particle transmission, i.e. whether the particle went out of the
last layer.
if(Di.x >= xx[Layer])
{
//particle is transmitted, take care of appropriate variables and break
transmitted = 1;//cout << “ion number “ << ih << “ transmitted.” << endl;
it = it + 1;
et = et + e;
ia = 57.295779 * acos(cosin) / da + 1.0;
ie = 100 * e / e0 + 1.0;
//m[ie][ia] = m[ie][ia] + 1;//note: how is this possible? ie and ia should be
integers in order to access the elements of the array m[][]. But we calculate them as
doubles here!
break; //break out of the ‘mother’ do loop
}
//now take care of ionCounter and other variables for the next scattering
if(neighborFlag == 0)
{
if(ionCounter == 3)
{
//ionCounter = 0;
neighborFlag = 1;
scatterIonPos = ions[3];
//cout << endl << “got out of first two layers” << endl;
}
else
{
ionCounter++;
}
}
if(neighborFlag == 1)
{
//cout << “Updating Neighbor Ions” << endl;
neighborIonsBCC[0] = scatterIonPos + lx - ly + lz;
neighborIonsBCC[1] = scatterIonPos + lx + ly + lz;
neighborIonsBCC[2] = scatterIonPos + lx + ly - lz;
neighborIonsBCC[3] = scatterIonPos + lx - ly - lz;
neighborIonsBCC[4] = scatterIonPos + lx * 2;
neighborIonsBCC[5] = scatterIonPos - lx - ly - lz;
neighborIonsBCC[6] = scatterIonPos - lx + ly - lz;
neighborIonsBCC[7] = scatterIonPos - lx + ly + lz;
neighborIonsBCC[8] = scatterIonPos - lx - ly + lz;
neighborIonsBCC[9] = scatterIonPos + lz * 2;
neighborIonsBCC[10] = scatterIonPos - lz * 2;
neighborIonsBCC[11] = scatterIonPos + ly * 2;
neighborIonsBCC[12] = scatterIonPos - ly * 2;
neighborIonsBCC[13] = scatterIonPos - lx * 2;
}
//set DiPrev to Di
DiPrev = Di;
//update current lambda to lambdaPrime
lambda = lambdaPrime;
//now the while condition of the mother do loop checks if the particle has lesser
energy than our lowest energy limit, ef.
}
while(e > ef);
//since we are out of the mother do loop now, the particle must have come to a
stop. So, increase the final particle distributions if the particle has not been
transmitted or backscattered.
if( ((transmitted == 0)) && ((backscattered == 0)) && ((insideChannel == 1)) )
{
ip = (int)(pl/cw + 1.0);
if(ip > 100) ip = 100;
//ipl[ip] = ipl[ip] + 1;
xsum = xsum + Di.x;
//my own bin function
selectedXBin = whichBin(Di.x, xx[Layer], numXBin);
//write the selected bin to the output file
//outStream << selectedXBin << endl;
//cout << x << endl << xx[Layer] << endl << numXBin << endl << selectedXBin;
xBin[selectedXBin] = xBin[selectedXBin] + 1;
//print final x value for plotting histogram
//cout << “ion “ << ih << “ final x: “ << Di.x << endl;
infoStream << “ion “ << ih << “ final x: “ << Di.x << endl;
//cout << Di.x << “,”;
rangeStream << Di.x << endl;
plsum = plsum + pl;
icsum = icsum + ic;
//ipl is the ion path length - the total avg. distance the ion travels
regardless of direction before it comes to stop
}
//that brings us to the end of one ion’s journey, now go to next ion by going back
to the for loop’s beginning..
}
//and this ends the monte carlo loop function. Take care of necessary structures and
variables that need to be cleared/deleted
outStream.close();
scatterStream.close();
infoStream << “Number of Backscattered Ions: “ << ib << endl;
infoStream.close();
rangeStream.close();
}
int whichNonUniformBin(double e, double arr[], int numBins)
{
double low = 0, high = arr[0];
if((e>=low) && (e<high))
return 0;
else
{
for(int i = 0; i < numBins; i++)
{
low += arr[i];
high += arr[i+1];
//cout << “\tlow: “ << low << “, high:” << high << endl;
if((e>=low) && (e<high))
return i;
}
}
}
129
//============================================================================
// Name : monte.cpp
// Author : Nazmus Saquib
// Version :
// Copyright :
// Description : BCA code in C++
//============================================================================
#include “Globals.h”
#include “scoef.h”
#include “rstop.h”
#include “muscle_bca.h”
#include “vectorGeometry.h”
const int numXBin = 100;
const int numIons = 1;
int xBin[numXBin+1] = {0};
int selectedXBin = 0;
double rho[4]={0.0};
int n[]={0,0,0,0};
double e0kev, m1, cw, ed, latticeConst;
int z1, hn, iy, nowout;
double dx[3] = {0.0};
int zt[3][7] = {0};
double mt[3][7] = {0.};
double t[3][7] = {0.};
int Layer; //use this for number of layers rather than the L in the program;
//remember this cannot be set to 0. Other loops/arrays may start from
//0, but keep this >= 1;
//the arrays..
double my[3][7]= {0},
ai[3][7]= {0},
fi[3][7]= {0},
ec[3][7]= {0},
io[3][7]= {0},
k[3]= {0},
kl[3][7]= {0};
double vf[3][7]= {0},
mu[3]= {0},
ioniz[3]= {0},
h[3]= {0},
xx[3]= {0},
m2[3]= {0.0},
z2[3]= {0},
c[3]= {0},
epsbk[3]= {0},
arho[3]= {0};
double a[3]= {0},
f[3]= {0},
lm[3]= {0},
pmax[3]= {0},
fd[3]= {0},
kd[3]= {0},
sbk[3]= {0},
lf[3]= {0},
yy[8]= {0};
double se[3][1000]= {0.0},
seo[1000]= {0.0},
epsdg[3]= {0.0};
double ls = 0., lo = 0., maximum = 0.;
double xsum = 0, x2sum = 0, x3sum = 0, x4sum = 0, plsum = 0, pl2sum = 0;
double avex = 0, vari = 0, sigma = 0, v = 0, v2 = 0, Gamma = 0, beta = 0, y = 0, avepl
= 0, sigpl = 0, avecol = 0;
int i = 0, j = 0;
int ib = 0, it = 0;
double eb = 0.0, et = 0.0;
int icsum = 0;
double y2sum = 0, xy2sum = 0, x2y2su = 0, y4sum = 0;
double tau = 0;
int iii = -1;
//my dummy vars
int w; double q;
//my customized data structures or vars
scoefData scoefz1;
rstopData rstp;
//these vars (continuing from this line) are added later as needed, vars that were not
declared in the initialization of trim85 but showed up in the middle.
double e0, ef;
int iz;
double alfa, alpha;
double tmin, da;
double L0;
int iz1;
double ee;
int izt;
double nh;
double epso;
int ih;
double e;
//boolean for keeping track of a particle being transmitted or backscattered
int transmitted = 0;
int backscattered = 0;
//boolean for keeping track of channeling
int insideChannel = 1;
//boolean for determining whether to scatter from neighbor atoms
int neighborFlag = 0;
//main function
int main()
{
cout << “Initializing” << endl;
Initialize(“IronInput.dat”);
calculateAvgMassOfLayer();
getStoppingForTarget();
setInitialConditions();
MonteCarlo();
/* *********************** Testing Ground for arrays and variables
******************** */
for (w = 1; w <= 8; w++) cout << “\t “ << yy[w];
for (w = 1; w <= 3; w++) cout << “\n\t “ << xx[w];
cout << “CW or L0: “ << L0;
//(trouble! The values of n[] elements are changing like crazy)
cout << endl << n[0] << “\t” << n[1] << “\t” << n[2] << “\t” << n[3] << endl;
cout << endl << rho[0] << “\t” << rho[1] << “\t” << rho[2] << “\t” << rho[3] <<
“\t” << rho[4] << endl;
//test z2[], m2[] arrays
for (w = 1; w <= Layer; w++) cout << “\t “ << z2[w];
for (w = 1; w <= Layer; w++) cout << “\n\t “ << m2[w];
//test the se values
cout << endl << se[1][1000] << “ “ << se[2][1000] << “ “ << se[3][1000] << endl;
//test the se[] values by printing 10th element from the array (to be implemented)
//for (w = 1; w <= 100; w++)
//{
//for (int sss = 1; sss <= 50; sss++)
//{
//cout << “\t” << mpart[w][sss];
//}
//}
/* *********************** End of Testing Ground ************************** */
cout << endl;
//Now print values of each bin in xBin
//for (w = 1; w <= numXBin; w++) cout << xBin[w] << “,”;
//print final x values
cout << endl;
cout << “Number of Backscattered Ions: “ << ib << endl;
cout << “Number of Transmitted Ions: “ << it << endl;
return 0;
}
//end of main
//Helper functions follow from here
//initialize variables and setup each layer over here
void Initialize(char* filename)
{
//Read command file
ifstream instream;
instream.open(filename,ios::in);
cout << filename;
if (!instream)
{
exitOnError(filename);
}
instream >> e0kev >> z1 >> m1 >> latticeConst >> hn >> cw >> ed >> iy >> nowout;
instream >> dx[1] >> rho[1];
instream >> zt[1][1] >> mt[1][1] >> t[1][1];
instream >> n[1];
instream >> dx[2] >> rho[2];
instream >> zt[2][1] >> mt[2][1] >> t[2][1];
instream >> n[2];
instream >> dx[3] >> rho[3];
instream >> zt[3][1] >> mt[3][1] >> t[3][1];
instream >> n[3];
for (w = 0; w <= 3; w++)
{ if (n[w] != 1) n[w] = 1; }
instream.close();
Layer = 3;
//done with primary (crude) setup, off to reading scoef.dat file
iz = z1;
getstructScoef(iz, scoefz1, “scoef1.dat”); //used to get pcoef data yy in trim85
//so we put the values in yy here immediately
for (w = 1; w <= 8; w++)
{ yy[w] = scoefz1.pcoef[w]; }
//note: although yy turns out to be just a dummy array
e0 = e0kev*1000; //convert to ev.
if (ed == 0.) ed = 25.0;
ef = Max(5.0, e0kev*0.1);
//alfa = angle of incidence, alpha = radian of alfa
alfa = 0.;
alpha = alfa*Pi/180;
tmin = 5.0;
tau = 0.0;
da = 3.0;
if (iy == 0) iy = 16381;
//now calculate the total depth of each layer = xx(l), and grid spacing cw
xx[1] = dx[1];
for (w = 2; w <= 3; w++) { xx[w] = dx[w] + xx[w-1]; }
if (cw == 0) cw = 0.01*xx[3];
L0 = cw;
//take care of any custom variable or struct I made
rstp.vfermi = 0.0; //set this to 0. for the time being (see log for explanation)
//now, off to avg mass of layer in the next void function
}
//avg mass and atomic number of each layer
void calculateAvgMassOfLayer()
{
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
h[LL] = h[LL] + t[LL][w];
//cout << “testing here..” << rstp.vfermi << endl;
}
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
t[LL][w] = t[LL][w]/h[LL];
m2[LL] = m2[LL] + t[LL][w] * mt[LL][w];
z2[LL] = z2[LL] + t[LL][w] * zt[LL][w];
//note: z2 wont be an integer once t has a value other than 1.0??
//so are we calculating average atomic number here? why?
}
}
//done with this, off to finding electronic stopping powers in the next function
}
void getStoppingForTarget()
{
iz1 = z1; ee = 0;
for (int LL = 1; LL <= Layer; LL++)
{
arho[LL] = rho[LL] * 0.6022/(m2[LL]);
mu[LL] = m1/(m2[LL]);
int ii = n[LL];
for (int nn = 1; nn <= ii; nn++)
{
//set rstp.se[1..1000] = 0. Clear it for the next loop
for (w = 1; w <= 1000; w++)
{ rstp.se[w] = 0.; }
izt = zt[LL][nn];
//calling getrstop now. units, lfctr, vfermi = 1 (doesnt matter)
getrStop(iz1, izt, e0kev, 1, 1., 1., rstp); //rstp defined in header
//set this anyway, though I dont calculate this in RSTOP
vf[LL][nn] = rstp.vfermi; //which is just set 0 in the struct def.
for (w = 1; w <= 1000; w++)
{
se[LL][w] = se[LL][w] + rstp.se[w] * t[LL][nn] * arho[LL];
}
}
}
//now, off to setting up initial conditions next function
}
void setInitialConditions()
{
nh = hn; //number of histories
for (int LL = 1; LL <= Layer; LL++)
{
a[LL] = 0.5292 * 0.8853 / ( pow(z1, 0.23) + pow(z2[LL], 0.23) );
//now calculate the mean flight path with the conditions given in trim85
f[LL] = a[LL] * m2[LL] / ( z1 * z2[LL] * 14.4 * (m1 + m2[LL] ) );
epso = e0 * f[LL];
epsdg[LL] = tmin * f[LL] * pow( (1.0 + mu[LL]) , 2) / (4.0 * mu[LL]);
fd[LL] = 0.01 * pow( z2[LL], (-7.0/3.0) );
kd[LL] = 0.1334 * pow ( z2[LL], (2.0/3.0) ) / sqrt( m2[LL] );
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
my[LL][w] = m1/mt[LL][w];
ec[LL][w] = 4.0 * my[LL][w] / pow( ( 1.0 + my[LL][w] ), 2);
ai[LL][w] = 0.5292 * 0.8853 / ( pow(z1,0.23) + pow(zt[LL][w],0.23) );
fi[LL][w] = ai[LL][w] * mt[LL][w] / ( z1 * zt[LL][w] * 14.4 * ( m1 + mt[LL][w] ) );
}
}
cout << “Setup finished. Starting Monte Carlo Loops..”;
//off to monte carlo loop in next routine
}
void MonteCarlo()
{
//custom variables and arrays for this section
double e;
double cosin = 0.0, siny = 0.0, sine = 0.0, cosy = 0.0;
double pl = 0.0;
int ic;
int LL = 1;
double eps;
double eeg;
double p;
double b;
int ie, ia; //not sure if ie or ia should be double. They are used to access elements
of the m[][] array at some point
double see;
double dee;
double s2, c2, ct, st;
double r, rr;
double ex1, ex2, ex3, ex4;
double v, v1;
double fr, fr1;
double q;
double roc, sqe;
double cc, aa, ff;
double delta, co;
double den;
double phi, psi;
double x1;
int ip;
//variables for crystal calculations
double sep = 0.0;
int ionCounter = 0;
double p1, p2;
double Theta = 0.0;
double rTheta = 0.0, rPhi = 0.0;
double thetaThreshold = 0.5;
double crystalMuonY = 0.0, crystalMuonZ = 0.0;
//amount of translations in y and z axes
double translationY = 0.0, translationZ = 0.0;
//Scatter Plot variables
const int numScatterPlotBins = 5;
double scatterPlot[numScatterPlotBins + 1] = {0.0};
//Vector declarations
//lattice constant of Target (input from file)
double latticeConstant = latticeConst;
Vector3 ions[4];
Vector3 ionsOrdered[4];
Vector3 neighborIonsBCC[14];
Vector3 neighborIonsFCC[14];
Vector3 ionTranslationY(0,translationY,0);
Vector3 ionTranslationZ(0,0,translationZ);
Vector3 unitzplus, unitzminus, unityplus, unityminus, unitxplus, unitxminus;
unitzplus.z = 1;
unitzminus.z = -1;
unityplus.y = 1;
unityminus.y = -1;
unitxplus.x = 1;
unitxminus.x = -1;
Vector3 initialDirection(1,0,0);
Vector3 d;
d.x = 1;
d *= latticeConstant/2;
Vector3 lx(latticeConstant/2, 0, 0);
Vector3 ly(0, latticeConstant/2, 0);
Vector3 lz(0, 0, latticeConstant/2);
Vector3 lambda;
Vector3 lambdaPrime;
Vector3 pVector;
Vector3 pUnitVector;
Vector3 sepVector;
Vector3 Di;
Vector3 DiPrev;
//Vector3 DiPrevToDi;
Vector3 delX;
Vector3 delX1, delX2;
Vector3 dummy1, dummy2, temp;
Vector3 scatterIonPos;
//initialize the random number generator
srand(time(NULL));
//open file to write output
ofstream outStream;
outStream.open(“coords0.txt”);
if(outStream.fail())
{
exitOnError(“Could not open Output file”);
}
//write basic information in the output file
//number of ions, ion energy, total depth, depth of each layer
outStream << nh << “\t” << e0kev << “\t” << xx[Layer] << “\t” << dx[1] << “\t”
<< dx[2] << “\t” << dx[3] << endl;
//open scatter plot file to write current Y and Z coordinates of muons at designated
intervals
ofstream scatterStream;
scatterStream.open(“scatterOut1.txt”);
if(scatterStream.fail())
{
exitOnError(“Could not open Scatter Plot Output file”);
}
//open range distribution file to write final X coordinates of muons
ofstream rangeStream;
rangeStream.open(“rangeOut1.txt”);
if(rangeStream.fail())
{
exitOnError(“Could not open Range Distribution Output file”);
}
//Open general information dump file
ofstream infoStream;
infoStream.open(“info1.txt”);
if(infoStream.fail())
{
exitOnError(“Could not open general information Output file”);
}
//Entering the target
//First set up for the top layer
for (ih = 1; ih <= nh; ih++)
{
avex = xsum / Max(1.0, (float)(ih - ib - it - 1));
if (talk == 2) cout << “Average ion range so far: “ << avex << “ angstroms.”
<<endl;
if (talk > 2) cout << “Now starting ion number “ << ih << endl;
e = e0;
//set scatterPlot array (the intervals)
scatterPlot[0] = 10;
scatterPlot[1] = 30;
scatterPlot[2] = 50;
scatterPlot[3] = 100;
scatterPlot[4] = 150;
scatterPlot[5] = 200;
/*
for(int ccc = 0; ccc <= numScatterPlotBins; ccc++)
{
cout << “scatter plot “ << ccc << “: “ << scatterPlot[ccc] << endl;
}
*/
//Initial Ion Positions
ions[0] = d + ionTranslationZ + unitzminus * (latticeConstant/2);
ions[1] = d + ionTranslationZ + unitzplus * (latticeConstant/2);
ions[2] = d * 2 + ionTranslationY + unityminus * (latticeConstant/2);
ions[3] = d * 2 + ionTranslationY + unityplus * (latticeConstant/2);
//Create a polygon that resides on the lateral axes.
//The points are put on anticlockwise order, which is important for
//testing whether the test point lies on this polygon
ionsOrdered[0] = ions[0];
ionsOrdered[1] = ions[2];
ionsOrdered[2] = ions[1];
ionsOrdered[3] = ions[3];
//generate random theta and phi angles.
rTheta = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * thetaThreshold;
rPhi = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * 2 * Pi;
//find corresponding x, y and z components of the direction vector.
//radius of the direction vector is 1
initialDirection.x = cos(rTheta);
initialDirection.z = sin(rTheta) * cos(rPhi);
initialDirection.y = sin(rTheta) * sin(rPhi);
//set the counter to 0 for a new ion
ionCounter = 0;
pl = 0.0;
ic = 0;
//set initial DiPrev - the origin
DiPrev.x = 0.0; DiPrev.y = 0.0; DiPrev.z = 0.0;
//set initial lambda, the direction of motion. Normalize it.
lambda.clear();
lambda = initialDirection;
lambda.normalize();
//set initial delX to origin
delX.clear();
//clear the dummy delX vectors, set them to origin
delX1.clear();
delX2.clear();
dummy1.clear();
dummy2.clear();
temp.clear();
LL = 1;
//set transmitted and backscattered to false
transmitted = 0;
backscattered = 0;
//set channeling to true
insideChannel = 1;
neighborFlag = 0;
//write the initial coordinates to the output file
outStream << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << endl << “Initial: “;
//cout << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << “r1 = “ << r1 << endl;
//cycle for each collision until the energy of the particle becomes too low, or
the particle backscatters, or it goes out of the last layer (transmission)
//needs a do while loop here,
//which I will mention as the ‘mother loop’ from now.
do
{
ic = ic + 1;
eps = e * f[LL];
eeg = sqrt(eps*epsdg[LL]);
//pmax[LL] = a[LL] / (eeg + sqrt(eeg) + 0.125 * pow( eeg, 0.1) );
pmax[LL] = sqrt(3) * (latticeConstant / 2) * 0.7;
//Calculate impact parameter and choose the atom to scatter from.
//Do this for ion pairs 0,1 and 2,3.
if (ionCounter == 0)
{
delX1 = ions[0] - DiPrev;
delX2 = ions[1] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[0];
ions[0] = ions[1];
ions[1] = temp;
//cout << “Vertical Ions swapped” << endl;
}
}
if (ionCounter == 2)
{
delX1 = ions[2] - DiPrev;
delX2 = ions[3] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[2];
ions[2] = ions[3];
ions[3] = temp;
//cout << “Horizontal Ions swapped” << endl;
}
}
//now calculate impact parameter
if(neighborFlag == 0)
{
delX = ions[ionCounter] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
else if(neighborFlag == 1)
{
double impact[13] = {0.0};
double radial[13] = {0.0};
double S[13] = {0.0};
double sumS = 0.0;
double Probability[13] = {0.0};
double rnd_candidate = 0.0;
int selected_candidate = -1;
for(int ncount = 0; ncount <= 13; ncount++)
{
delX = neighborIonsBCC[ncount] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
//scatterIonPos = neighborIonsBCC[ncount];
impact[ncount] = p;
radial[ncount] = delX.magnitude();
S[ncount] = 1 / ( pow(impact[ncount],2) * radial[ncount] );
sumS += S[ncount];
//general scheme of selecting the neighbor ion
// if(p < pmax[LL])
// {
// scatterIonPos = neighborIonsBCC[ncount];
// //cout << “Neighbor “ << ncount << “ is selected” << endl;
// break;
// }
}
for(int ncount = 0; ncount <= 13; ncount++)
{
Probability[ncount] = S[ncount] / sumS;
}
//print out the probability array
cout << endl;
for(int ncount = 0; ncount <= 13; ncount++)
{
//cout << Probability[ncount] << “ “;
infoStream << Probability[ncount] << “ “;
}
infoStream << endl;
//cout << endl;
//random number between 0 and 1
rnd_candidate = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) );
//cout << “rand_candidate: “ << rnd_candidate << endl;
//choose the candidate for scattering
selected_candidate = whichNonUniformBin(rnd_candidate, Probability, 13);
//cout << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate <<
endl;
infoStream << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate
<< endl;
//assign the scatterIonPos variable to the selected neighbor
scatterIonPos = neighborIonsBCC[selected_candidate];
//cout << “Scattering Ion Position: “; scatterIonPos.printVector();
//find the essential quantities for the selected neighbor
delX = neighborIonsBCC[selected_candidate] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
//find eps and b using fi[LL][nn], using nn that I was supposed to find from above
//here im deliberately using nn = 1
eps = fi[LL][1] * e;
b = p / ai[LL][1];
if (eps > 10) //rutherford scattering
{
s2 = 1.0 / (1.0 + (1.0 + b * (1.0 + b)) * pow((2.0 * eps * b), 2) );
c2 = 1.0 - s2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
else //magic formula
{
r = b;
rr = -2.7 * log(eps * b);
if (rr >= b)//note >= sign instead < in trim85
{
rr = -2.7 * log(eps * rr);
if (rr >= b)//note >= sign instead < in trim85
{
r = rr;
}
}
//do while loop that replaces line 330 loop
do
{
ex1 = 0.18175 * exp(-3.1998 * r);
ex2 = 0.50986 * exp(-0.94229 * r);
ex3 = 0.28022 * exp(-0.4029 * r);
ex4 = 0.028171 * exp(-0.20162 * r);
v = (ex1 + ex2 + ex3 + ex4) / r;
v1 = -(v + 3.1998 * ex1 + 0.94229 * ex2 + 0.4029 * ex3 + 0.20162 * ex4) / r;
fr = b * b / r + v * r / eps - r;
fr1 = -b * b / (r * r) + (v + v1 * r) / eps - 1.0;
q = fr / fr1;
r = r - q;
}
while( (Abs(q / r)) > 0.001 );
roc = -2.0 * (eps - v) / v1;
sqe = sqrt(eps);
//5 parameter magic scattering calculation
//below is for universal potential
cc = (0.011615 + sqe) / (0.0071222 + sqe);
aa = 2.0 * eps * (1.0 + (0.99229 / sqe) ) * ( pow(b, cc) );
ff = ( sqrt(aa * aa + 1.0) - aa) * ( (9.3066 + eps) / (14.813 + eps) );
delta = (r - b) * aa * ff / (ff + 1.0);
co = (b + delta + roc) / (r + roc);
c2 = co * co;
s2 = 1.0 - c2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
Theta = acos(ct);
//we are done finding theta (in CM system). So calculate all other quantities.
//find separation and the separation vector.
phi = (Pi - Theta) / 2;
sep = p / tan(phi);
sepVector = lambda * sep;
//find theta in laboratory frame - psi
psi = atan(st / (ct + my[LL][1] ) );
//note: change my[LL][1] to my[LL][nn] when the above section is fixed.
if (psi < 0 ) psi = psi + Pi; //should I do this for crystals?
//find Di, the scattering point vector
Di = DiPrev + delX + pVector - sepVector;
//find new direction of motion
lambdaPrime = lambda * cos(psi) + pUnitVector * sin(psi);
lambdaPrime.normalize();
//find length of step, ls = distance of Di from DiPrev
ls = Di.getDistance(DiPrev);
//find energy lost due to electronic stopping, dee
ie = (int)(e/e0kev+0.5); //should it be 0.5? or less so that ie <=1000?
see = se[LL][ie];
if (e < e0kev) see = se[LL][1] * sqrt(e/e0kev);
dee = ls * see;
// den = energy transferred to recoil
den = ec[LL][1] * s2 * e; //note: I am using ec[LL][1] here instead of [LL][nn].
//cout << “den = “ << den << “, dee = “ << dee << endl;
infoStream << “den = “ << den << “, dee = “ << dee << endl;
e = e - den - dee;
//cout << endl<< “current ion energy: “ << e << endl;
if (dee > maximum) maximum = dee;
pl = pl + ls - tau;
//write the ion position to output file
outStream << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
if((ic%30)==0)
{
//cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
}
//determine which scatter plot Di’s x value belongs to.
//output the y and z coordinates to scatter plot file accordingly.
for(int cc = 0; cc <= numScatterPlotBins; cc++)
{
if( Di.x >= (scatterPlot[cc]) )
{
crystalMuonY = Di.y - translationY;
crystalMuonZ = Di.z - translationZ;
//cout << “scatter plot “ << ct << “: “ << scatterPlot[ct] << endl;
scatterStream << scatterPlot[cc] << “\t” << crystalMuonY << “\t” <<
crystalMuonZ << endl;
//set scatterPlot[ss] to a big number
scatterPlot[cc] = 10000;
//break out of this for loop
break;
}
}
//determine if Di is in the channeling region.
//insideChannel = Di.isInsidePolygon(ionsOrdered, 4);
//break out of parent loop if not inside the channel
if(insideChannel == 0)
{
cout << “Ion “ << ih << “ is out of Channel” << endl;
cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
break;
}
//determine which layer the next collision will be in
if (Di.x < 0.0) //particle is backscattered
{
backscattered = 1; //cout << “ion number “ << ih << “ backscattered.” << endl;
infoStream << “ion number “ << ih << “ backscattered.” << endl;
ib = ib + 1;
eb = eb + e;
break; //break out of ‘mother do loop’ and continue with the next session of
for loop.
}
//here we set the current or next layer the particle will be in
for (w = 1; w <= Layer; w++)
{
if ( (Di.x <= xx[w]) && (w == 1) )
{
LL = 1;
//cout << endl<<”ion is in layer “ << LL << endl;
break;
//break out of this For loop and go check if the particle is transmitted.
}
else if ( (Di.x <= xx[w]) && (Di.x > xx[w-1]) )
{
LL = w;
//cout << “ion is in layer “ << LL <<endl;
break; //break out of this For loop and go check if the particle is
transmitted.
}
}
//now, check for particle transmission, i.e. whether the particle went out of the
last layer.
if(Di.x >= xx[Layer])
{
//particle is transmitted, take care of appropriate variables and break
transmitted = 1;//cout << “ion number “ << ih << “ transmitted.” << endl;
it = it + 1;
et = et + e;
ia = 57.295779 * acos(cosin) / da + 1.0;
ie = 100 * e / e0 + 1.0;
//m[ie][ia] = m[ie][ia] + 1;//note: how is this possible? ie and ia should be
integers in order to access the elements of the array m[][]. But we calculate them as
doubles here!
break; //break out of the ‘mother’ do loop
}
//now take care of ionCounter and other variables for the next scattering
if(neighborFlag == 0)
{
if(ionCounter == 3)
{
//ionCounter = 0;
neighborFlag = 1;
scatterIonPos = ions[3];
//cout << endl << “got out of first two layers” << endl;
}
else
{
ionCounter++;
}
}
if(neighborFlag == 1)
{
//cout << “Updating Neighbor Ions” << endl;
neighborIonsBCC[0] = scatterIonPos + lx - ly + lz;
neighborIonsBCC[1] = scatterIonPos + lx + ly + lz;
neighborIonsBCC[2] = scatterIonPos + lx + ly - lz;
neighborIonsBCC[3] = scatterIonPos + lx - ly - lz;
neighborIonsBCC[4] = scatterIonPos + lx * 2;
neighborIonsBCC[5] = scatterIonPos - lx - ly - lz;
neighborIonsBCC[6] = scatterIonPos - lx + ly - lz;
neighborIonsBCC[7] = scatterIonPos - lx + ly + lz;
neighborIonsBCC[8] = scatterIonPos - lx - ly + lz;
neighborIonsBCC[9] = scatterIonPos + lz * 2;
neighborIonsBCC[10] = scatterIonPos - lz * 2;
neighborIonsBCC[11] = scatterIonPos + ly * 2;
neighborIonsBCC[12] = scatterIonPos - ly * 2;
neighborIonsBCC[13] = scatterIonPos - lx * 2;
}
//set DiPrev to Di
DiPrev = Di;
//update current lambda to lambdaPrime
lambda = lambdaPrime;
//now the while condition of the mother do loop checks if the particle has lesser
energy than our lowest energy limit, ef.
}
while(e > ef);
//since we are out of the mother do loop now, the particle must have come to a
stop. So, increase the final particle distributions if the particle has not been
transmitted or backscattered.
if( ((transmitted == 0)) && ((backscattered == 0)) && ((insideChannel == 1)) )
{
ip = (int)(pl/cw + 1.0);
if(ip > 100) ip = 100;
//ipl[ip] = ipl[ip] + 1;
xsum = xsum + Di.x;
//my own bin function
selectedXBin = whichBin(Di.x, xx[Layer], numXBin);
//write the selected bin to the output file
//outStream << selectedXBin << endl;
//cout << x << endl << xx[Layer] << endl << numXBin << endl << selectedXBin;
xBin[selectedXBin] = xBin[selectedXBin] + 1;
//print final x value for plotting histogram
//cout << “ion “ << ih << “ final x: “ << Di.x << endl;
infoStream << “ion “ << ih << “ final x: “ << Di.x << endl;
//cout << Di.x << “,”;
rangeStream << Di.x << endl;
plsum = plsum + pl;
icsum = icsum + ic;
//ipl is the ion path length - the total avg. distance the ion travels
regardless of direction before it comes to stop
}
//that brings us to the end of one ion’s journey, now go to next ion by going back
to the for loop’s beginning..
}
//and this ends the monte carlo loop function. Take care of necessary structures and
variables that need to be cleared/deleted
outStream.close();
scatterStream.close();
infoStream << “Number of Backscattered Ions: “ << ib << endl;
infoStream.close();
rangeStream.close();
}
int whichNonUniformBin(double e, double arr[], int numBins)
{
double low = 0, high = arr[0];
if((e>=low) && (e<high))
return 0;
else
{
for(int i = 0; i < numBins; i++)
{
low += arr[i];
high += arr[i+1];
//cout << “\tlow: “ << low << “, high:” << high << endl;
if((e>=low) && (e<high))
return i;
}
}
}
130
//============================================================================
// Name : monte.cpp
// Author : Nazmus Saquib
// Version :
// Copyright :
// Description : BCA code in C++
//============================================================================
#include “Globals.h”
#include “scoef.h”
#include “rstop.h”
#include “muscle_bca.h”
#include “vectorGeometry.h”
const int numXBin = 100;
const int numIons = 1;
int xBin[numXBin+1] = {0};
int selectedXBin = 0;
double rho[4]={0.0};
int n[]={0,0,0,0};
double e0kev, m1, cw, ed, latticeConst;
int z1, hn, iy, nowout;
double dx[3] = {0.0};
int zt[3][7] = {0};
double mt[3][7] = {0.};
double t[3][7] = {0.};
int Layer; //use this for number of layers rather than the L in the program;
//remember this cannot be set to 0. Other loops/arrays may start from
//0, but keep this >= 1;
//the arrays..
double my[3][7]= {0},
ai[3][7]= {0},
fi[3][7]= {0},
ec[3][7]= {0},
io[3][7]= {0},
k[3]= {0},
kl[3][7]= {0};
double vf[3][7]= {0},
mu[3]= {0},
ioniz[3]= {0},
h[3]= {0},
xx[3]= {0},
m2[3]= {0.0},
z2[3]= {0},
c[3]= {0},
epsbk[3]= {0},
arho[3]= {0};
double a[3]= {0},
f[3]= {0},
lm[3]= {0},
pmax[3]= {0},
fd[3]= {0},
kd[3]= {0},
sbk[3]= {0},
lf[3]= {0},
yy[8]= {0};
double se[3][1000]= {0.0},
seo[1000]= {0.0},
epsdg[3]= {0.0};
double ls = 0., lo = 0., maximum = 0.;
double xsum = 0, x2sum = 0, x3sum = 0, x4sum = 0, plsum = 0, pl2sum = 0;
double avex = 0, vari = 0, sigma = 0, v = 0, v2 = 0, Gamma = 0, beta = 0, y = 0, avepl
= 0, sigpl = 0, avecol = 0;
int i = 0, j = 0;
int ib = 0, it = 0;
double eb = 0.0, et = 0.0;
int icsum = 0;
double y2sum = 0, xy2sum = 0, x2y2su = 0, y4sum = 0;
double tau = 0;
int iii = -1;
//my dummy vars
int w; double q;
//my customized data structures or vars
scoefData scoefz1;
rstopData rstp;
//these vars (continuing from this line) are added later as needed, vars that were not
declared in the initialization of trim85 but showed up in the middle.
double e0, ef;
int iz;
double alfa, alpha;
double tmin, da;
double L0;
int iz1;
double ee;
int izt;
double nh;
double epso;
int ih;
double e;
//boolean for keeping track of a particle being transmitted or backscattered
int transmitted = 0;
int backscattered = 0;
//boolean for keeping track of channeling
int insideChannel = 1;
//boolean for determining whether to scatter from neighbor atoms
int neighborFlag = 0;
//main function
int main()
{
cout << “Initializing” << endl;
Initialize(“IronInput.dat”);
calculateAvgMassOfLayer();
getStoppingForTarget();
setInitialConditions();
MonteCarlo();
/* *********************** Testing Ground for arrays and variables
******************** */
for (w = 1; w <= 8; w++) cout << “\t “ << yy[w];
for (w = 1; w <= 3; w++) cout << “\n\t “ << xx[w];
cout << “CW or L0: “ << L0;
//(trouble! The values of n[] elements are changing like crazy)
cout << endl << n[0] << “\t” << n[1] << “\t” << n[2] << “\t” << n[3] << endl;
cout << endl << rho[0] << “\t” << rho[1] << “\t” << rho[2] << “\t” << rho[3] <<
“\t” << rho[4] << endl;
//test z2[], m2[] arrays
for (w = 1; w <= Layer; w++) cout << “\t “ << z2[w];
for (w = 1; w <= Layer; w++) cout << “\n\t “ << m2[w];
//test the se values
cout << endl << se[1][1000] << “ “ << se[2][1000] << “ “ << se[3][1000] << endl;
//test the se[] values by printing 10th element from the array (to be implemented)
//for (w = 1; w <= 100; w++)
//{
//for (int sss = 1; sss <= 50; sss++)
//{
//cout << “\t” << mpart[w][sss];
//}
//}
/* *********************** End of Testing Ground ************************** */
cout << endl;
//Now print values of each bin in xBin
//for (w = 1; w <= numXBin; w++) cout << xBin[w] << “,”;
//print final x values
cout << endl;
cout << “Number of Backscattered Ions: “ << ib << endl;
cout << “Number of Transmitted Ions: “ << it << endl;
return 0;
}
//end of main
//Helper functions follow from here
//initialize variables and setup each layer over here
void Initialize(char* filename)
{
//Read command file
ifstream instream;
instream.open(filename,ios::in);
cout << filename;
if (!instream)
{
exitOnError(filename);
}
instream >> e0kev >> z1 >> m1 >> latticeConst >> hn >> cw >> ed >> iy >> nowout;
instream >> dx[1] >> rho[1];
instream >> zt[1][1] >> mt[1][1] >> t[1][1];
instream >> n[1];
instream >> dx[2] >> rho[2];
instream >> zt[2][1] >> mt[2][1] >> t[2][1];
instream >> n[2];
instream >> dx[3] >> rho[3];
instream >> zt[3][1] >> mt[3][1] >> t[3][1];
instream >> n[3];
for (w = 0; w <= 3; w++)
{ if (n[w] != 1) n[w] = 1; }
instream.close();
Layer = 3;
//done with primary (crude) setup, off to reading scoef.dat file
iz = z1;
getstructScoef(iz, scoefz1, “scoef1.dat”); //used to get pcoef data yy in trim85
//so we put the values in yy here immediately
for (w = 1; w <= 8; w++)
{ yy[w] = scoefz1.pcoef[w]; }
//note: although yy turns out to be just a dummy array
e0 = e0kev*1000; //convert to ev.
if (ed == 0.) ed = 25.0;
ef = Max(5.0, e0kev*0.1);
//alfa = angle of incidence, alpha = radian of alfa
alfa = 0.;
alpha = alfa*Pi/180;
tmin = 5.0;
tau = 0.0;
da = 3.0;
if (iy == 0) iy = 16381;
//now calculate the total depth of each layer = xx(l), and grid spacing cw
xx[1] = dx[1];
for (w = 2; w <= 3; w++) { xx[w] = dx[w] + xx[w-1]; }
if (cw == 0) cw = 0.01*xx[3];
L0 = cw;
//take care of any custom variable or struct I made
rstp.vfermi = 0.0; //set this to 0. for the time being (see log for explanation)
//now, off to avg mass of layer in the next void function
}
//avg mass and atomic number of each layer
void calculateAvgMassOfLayer()
{
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
h[LL] = h[LL] + t[LL][w];
//cout << “testing here..” << rstp.vfermi << endl;
}
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
t[LL][w] = t[LL][w]/h[LL];
m2[LL] = m2[LL] + t[LL][w] * mt[LL][w];
z2[LL] = z2[LL] + t[LL][w] * zt[LL][w];
//note: z2 wont be an integer once t has a value other than 1.0??
//so are we calculating average atomic number here? why?
}
}
//done with this, off to finding electronic stopping powers in the next function
}
void getStoppingForTarget()
{
iz1 = z1; ee = 0;
for (int LL = 1; LL <= Layer; LL++)
{
arho[LL] = rho[LL] * 0.6022/(m2[LL]);
mu[LL] = m1/(m2[LL]);
int ii = n[LL];
for (int nn = 1; nn <= ii; nn++)
{
//set rstp.se[1..1000] = 0. Clear it for the next loop
for (w = 1; w <= 1000; w++)
{ rstp.se[w] = 0.; }
izt = zt[LL][nn];
//calling getrstop now. units, lfctr, vfermi = 1 (doesnt matter)
getrStop(iz1, izt, e0kev, 1, 1., 1., rstp); //rstp defined in header
//set this anyway, though I dont calculate this in RSTOP
vf[LL][nn] = rstp.vfermi; //which is just set 0 in the struct def.
for (w = 1; w <= 1000; w++)
{
se[LL][w] = se[LL][w] + rstp.se[w] * t[LL][nn] * arho[LL];
}
}
}
//now, off to setting up initial conditions next function
}
void setInitialConditions()
{
nh = hn; //number of histories
for (int LL = 1; LL <= Layer; LL++)
{
a[LL] = 0.5292 * 0.8853 / ( pow(z1, 0.23) + pow(z2[LL], 0.23) );
//now calculate the mean flight path with the conditions given in trim85
f[LL] = a[LL] * m2[LL] / ( z1 * z2[LL] * 14.4 * (m1 + m2[LL] ) );
epso = e0 * f[LL];
epsdg[LL] = tmin * f[LL] * pow( (1.0 + mu[LL]) , 2) / (4.0 * mu[LL]);
fd[LL] = 0.01 * pow( z2[LL], (-7.0/3.0) );
kd[LL] = 0.1334 * pow ( z2[LL], (2.0/3.0) ) / sqrt( m2[LL] );
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
my[LL][w] = m1/mt[LL][w];
ec[LL][w] = 4.0 * my[LL][w] / pow( ( 1.0 + my[LL][w] ), 2);
ai[LL][w] = 0.5292 * 0.8853 / ( pow(z1,0.23) + pow(zt[LL][w],0.23) );
fi[LL][w] = ai[LL][w] * mt[LL][w] / ( z1 * zt[LL][w] * 14.4 * ( m1 + mt[LL][w] ) );
}
}
cout << “Setup finished. Starting Monte Carlo Loops..”;
//off to monte carlo loop in next routine
}
void MonteCarlo()
{
//custom variables and arrays for this section
double e;
double cosin = 0.0, siny = 0.0, sine = 0.0, cosy = 0.0;
double pl = 0.0;
int ic;
int LL = 1;
double eps;
double eeg;
double p;
double b;
int ie, ia; //not sure if ie or ia should be double. They are used to access elements
of the m[][] array at some point
double see;
double dee;
double s2, c2, ct, st;
double r, rr;
double ex1, ex2, ex3, ex4;
double v, v1;
double fr, fr1;
double q;
double roc, sqe;
double cc, aa, ff;
double delta, co;
double den;
double phi, psi;
double x1;
int ip;
//variables for crystal calculations
double sep = 0.0;
int ionCounter = 0;
double p1, p2;
double Theta = 0.0;
double rTheta = 0.0, rPhi = 0.0;
double thetaThreshold = 0.5;
double crystalMuonY = 0.0, crystalMuonZ = 0.0;
//amount of translations in y and z axes
double translationY = 0.0, translationZ = 0.0;
//Scatter Plot variables
const int numScatterPlotBins = 5;
double scatterPlot[numScatterPlotBins + 1] = {0.0};
//Vector declarations
//lattice constant of Target (input from file)
double latticeConstant = latticeConst;
Vector3 ions[4];
Vector3 ionsOrdered[4];
Vector3 neighborIonsBCC[14];
Vector3 neighborIonsFCC[14];
Vector3 ionTranslationY(0,translationY,0);
Vector3 ionTranslationZ(0,0,translationZ);
Vector3 unitzplus, unitzminus, unityplus, unityminus, unitxplus, unitxminus;
unitzplus.z = 1;
unitzminus.z = -1;
unityplus.y = 1;
unityminus.y = -1;
unitxplus.x = 1;
unitxminus.x = -1;
Vector3 initialDirection(1,0,0);
Vector3 d;
d.x = 1;
d *= latticeConstant/2;
Vector3 lx(latticeConstant/2, 0, 0);
Vector3 ly(0, latticeConstant/2, 0);
Vector3 lz(0, 0, latticeConstant/2);
Vector3 lambda;
Vector3 lambdaPrime;
Vector3 pVector;
Vector3 pUnitVector;
Vector3 sepVector;
Vector3 Di;
Vector3 DiPrev;
//Vector3 DiPrevToDi;
Vector3 delX;
Vector3 delX1, delX2;
Vector3 dummy1, dummy2, temp;
Vector3 scatterIonPos;
//initialize the random number generator
srand(time(NULL));
//open file to write output
ofstream outStream;
outStream.open(“coords0.txt”);
if(outStream.fail())
{
exitOnError(“Could not open Output file”);
}
//write basic information in the output file
//number of ions, ion energy, total depth, depth of each layer
outStream << nh << “\t” << e0kev << “\t” << xx[Layer] << “\t” << dx[1] << “\t”
<< dx[2] << “\t” << dx[3] << endl;
//open scatter plot file to write current Y and Z coordinates of muons at designated
intervals
ofstream scatterStream;
scatterStream.open(“scatterOut1.txt”);
if(scatterStream.fail())
{
exitOnError(“Could not open Scatter Plot Output file”);
}
//open range distribution file to write final X coordinates of muons
ofstream rangeStream;
rangeStream.open(“rangeOut1.txt”);
if(rangeStream.fail())
{
exitOnError(“Could not open Range Distribution Output file”);
}
//Open general information dump file
ofstream infoStream;
infoStream.open(“info1.txt”);
if(infoStream.fail())
{
exitOnError(“Could not open general information Output file”);
}
//Entering the target
//First set up for the top layer
for (ih = 1; ih <= nh; ih++)
{
avex = xsum / Max(1.0, (float)(ih - ib - it - 1));
if (talk == 2) cout << “Average ion range so far: “ << avex << “ angstroms.”
<<endl;
if (talk > 2) cout << “Now starting ion number “ << ih << endl;
e = e0;
//set scatterPlot array (the intervals)
scatterPlot[0] = 10;
scatterPlot[1] = 30;
scatterPlot[2] = 50;
scatterPlot[3] = 100;
scatterPlot[4] = 150;
scatterPlot[5] = 200;
/*
for(int ccc = 0; ccc <= numScatterPlotBins; ccc++)
{
cout << “scatter plot “ << ccc << “: “ << scatterPlot[ccc] << endl;
}
*/
//Initial Ion Positions
ions[0] = d + ionTranslationZ + unitzminus * (latticeConstant/2);
ions[1] = d + ionTranslationZ + unitzplus * (latticeConstant/2);
ions[2] = d * 2 + ionTranslationY + unityminus * (latticeConstant/2);
ions[3] = d * 2 + ionTranslationY + unityplus * (latticeConstant/2);
//Create a polygon that resides on the lateral axes.
//The points are put on anticlockwise order, which is important for
//testing whether the test point lies on this polygon
ionsOrdered[0] = ions[0];
ionsOrdered[1] = ions[2];
ionsOrdered[2] = ions[1];
ionsOrdered[3] = ions[3];
//generate random theta and phi angles.
rTheta = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * thetaThreshold;
rPhi = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * 2 * Pi;
//find corresponding x, y and z components of the direction vector.
//radius of the direction vector is 1
initialDirection.x = cos(rTheta);
initialDirection.z = sin(rTheta) * cos(rPhi);
initialDirection.y = sin(rTheta) * sin(rPhi);
//set the counter to 0 for a new ion
ionCounter = 0;
pl = 0.0;
ic = 0;
//set initial DiPrev - the origin
DiPrev.x = 0.0; DiPrev.y = 0.0; DiPrev.z = 0.0;
//set initial lambda, the direction of motion. Normalize it.
lambda.clear();
lambda = initialDirection;
lambda.normalize();
//set initial delX to origin
delX.clear();
//clear the dummy delX vectors, set them to origin
delX1.clear();
delX2.clear();
dummy1.clear();
dummy2.clear();
temp.clear();
LL = 1;
//set transmitted and backscattered to false
transmitted = 0;
backscattered = 0;
//set channeling to true
insideChannel = 1;
neighborFlag = 0;
//write the initial coordinates to the output file
outStream << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << endl << “Initial: “;
//cout << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << “r1 = “ << r1 << endl;
//cycle for each collision until the energy of the particle becomes too low, or
the particle backscatters, or it goes out of the last layer (transmission)
//needs a do while loop here,
//which I will mention as the ‘mother loop’ from now.
do
{
ic = ic + 1;
eps = e * f[LL];
eeg = sqrt(eps*epsdg[LL]);
//pmax[LL] = a[LL] / (eeg + sqrt(eeg) + 0.125 * pow( eeg, 0.1) );
pmax[LL] = sqrt(3) * (latticeConstant / 2) * 0.7;
//Calculate impact parameter and choose the atom to scatter from.
//Do this for ion pairs 0,1 and 2,3.
if (ionCounter == 0)
{
delX1 = ions[0] - DiPrev;
delX2 = ions[1] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[0];
ions[0] = ions[1];
ions[1] = temp;
//cout << “Vertical Ions swapped” << endl;
}
}
if (ionCounter == 2)
{
delX1 = ions[2] - DiPrev;
delX2 = ions[3] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[2];
ions[2] = ions[3];
ions[3] = temp;
//cout << “Horizontal Ions swapped” << endl;
}
}
//now calculate impact parameter
if(neighborFlag == 0)
{
delX = ions[ionCounter] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
else if(neighborFlag == 1)
{
double impact[13] = {0.0};
double radial[13] = {0.0};
double S[13] = {0.0};
double sumS = 0.0;
double Probability[13] = {0.0};
double rnd_candidate = 0.0;
int selected_candidate = -1;
for(int ncount = 0; ncount <= 13; ncount++)
{
delX = neighborIonsBCC[ncount] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
//scatterIonPos = neighborIonsBCC[ncount];
impact[ncount] = p;
radial[ncount] = delX.magnitude();
S[ncount] = 1 / ( pow(impact[ncount],2) * radial[ncount] );
sumS += S[ncount];
//general scheme of selecting the neighbor ion
// if(p < pmax[LL])
// {
// scatterIonPos = neighborIonsBCC[ncount];
// //cout << “Neighbor “ << ncount << “ is selected” << endl;
// break;
// }
}
for(int ncount = 0; ncount <= 13; ncount++)
{
Probability[ncount] = S[ncount] / sumS;
}
//print out the probability array
cout << endl;
for(int ncount = 0; ncount <= 13; ncount++)
{
//cout << Probability[ncount] << “ “;
infoStream << Probability[ncount] << “ “;
}
infoStream << endl;
//cout << endl;
//random number between 0 and 1
rnd_candidate = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) );
//cout << “rand_candidate: “ << rnd_candidate << endl;
//choose the candidate for scattering
selected_candidate = whichNonUniformBin(rnd_candidate, Probability, 13);
//cout << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate <<
endl;
infoStream << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate
<< endl;
//assign the scatterIonPos variable to the selected neighbor
scatterIonPos = neighborIonsBCC[selected_candidate];
//cout << “Scattering Ion Position: “; scatterIonPos.printVector();
//find the essential quantities for the selected neighbor
delX = neighborIonsBCC[selected_candidate] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
//find eps and b using fi[LL][nn], using nn that I was supposed to find from above
//here im deliberately using nn = 1
eps = fi[LL][1] * e;
b = p / ai[LL][1];
if (eps > 10) //rutherford scattering
{
s2 = 1.0 / (1.0 + (1.0 + b * (1.0 + b)) * pow((2.0 * eps * b), 2) );
c2 = 1.0 - s2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
else //magic formula
{
r = b;
rr = -2.7 * log(eps * b);
if (rr >= b)//note >= sign instead < in trim85
{
rr = -2.7 * log(eps * rr);
if (rr >= b)//note >= sign instead < in trim85
{
r = rr;
}
}
//do while loop that replaces line 330 loop
do
{
ex1 = 0.18175 * exp(-3.1998 * r);
ex2 = 0.50986 * exp(-0.94229 * r);
ex3 = 0.28022 * exp(-0.4029 * r);
ex4 = 0.028171 * exp(-0.20162 * r);
v = (ex1 + ex2 + ex3 + ex4) / r;
v1 = -(v + 3.1998 * ex1 + 0.94229 * ex2 + 0.4029 * ex3 + 0.20162 * ex4) / r;
fr = b * b / r + v * r / eps - r;
fr1 = -b * b / (r * r) + (v + v1 * r) / eps - 1.0;
q = fr / fr1;
r = r - q;
}
while( (Abs(q / r)) > 0.001 );
roc = -2.0 * (eps - v) / v1;
sqe = sqrt(eps);
//5 parameter magic scattering calculation
//below is for universal potential
cc = (0.011615 + sqe) / (0.0071222 + sqe);
aa = 2.0 * eps * (1.0 + (0.99229 / sqe) ) * ( pow(b, cc) );
ff = ( sqrt(aa * aa + 1.0) - aa) * ( (9.3066 + eps) / (14.813 + eps) );
delta = (r - b) * aa * ff / (ff + 1.0);
co = (b + delta + roc) / (r + roc);
c2 = co * co;
s2 = 1.0 - c2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
Theta = acos(ct);
//we are done finding theta (in CM system). So calculate all other quantities.
//find separation and the separation vector.
phi = (Pi - Theta) / 2;
sep = p / tan(phi);
sepVector = lambda * sep;
//find theta in laboratory frame - psi
psi = atan(st / (ct + my[LL][1] ) );
//note: change my[LL][1] to my[LL][nn] when the above section is fixed.
if (psi < 0 ) psi = psi + Pi; //should I do this for crystals?
//find Di, the scattering point vector
Di = DiPrev + delX + pVector - sepVector;
//find new direction of motion
lambdaPrime = lambda * cos(psi) + pUnitVector * sin(psi);
lambdaPrime.normalize();
//find length of step, ls = distance of Di from DiPrev
ls = Di.getDistance(DiPrev);
//find energy lost due to electronic stopping, dee
ie = (int)(e/e0kev+0.5); //should it be 0.5? or less so that ie <=1000?
see = se[LL][ie];
if (e < e0kev) see = se[LL][1] * sqrt(e/e0kev);
dee = ls * see;
// den = energy transferred to recoil
den = ec[LL][1] * s2 * e; //note: I am using ec[LL][1] here instead of [LL][nn].
//cout << “den = “ << den << “, dee = “ << dee << endl;
infoStream << “den = “ << den << “, dee = “ << dee << endl;
e = e - den - dee;
//cout << endl<< “current ion energy: “ << e << endl;
if (dee > maximum) maximum = dee;
pl = pl + ls - tau;
//write the ion position to output file
outStream << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
if((ic%30)==0)
{
//cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
}
//determine which scatter plot Di’s x value belongs to.
//output the y and z coordinates to scatter plot file accordingly.
for(int cc = 0; cc <= numScatterPlotBins; cc++)
{
if( Di.x >= (scatterPlot[cc]) )
{
crystalMuonY = Di.y - translationY;
crystalMuonZ = Di.z - translationZ;
//cout << “scatter plot “ << ct << “: “ << scatterPlot[ct] << endl;
scatterStream << scatterPlot[cc] << “\t” << crystalMuonY << “\t” <<
crystalMuonZ << endl;
//set scatterPlot[ss] to a big number
scatterPlot[cc] = 10000;
//break out of this for loop
break;
}
}
//determine if Di is in the channeling region.
//insideChannel = Di.isInsidePolygon(ionsOrdered, 4);
//break out of parent loop if not inside the channel
if(insideChannel == 0)
{
cout << “Ion “ << ih << “ is out of Channel” << endl;
cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
break;
}
//determine which layer the next collision will be in
if (Di.x < 0.0) //particle is backscattered
{
backscattered = 1; //cout << “ion number “ << ih << “ backscattered.” << endl;
infoStream << “ion number “ << ih << “ backscattered.” << endl;
ib = ib + 1;
eb = eb + e;
break; //break out of ‘mother do loop’ and continue with the next session of
for loop.
}
//here we set the current or next layer the particle will be in
for (w = 1; w <= Layer; w++)
{
if ( (Di.x <= xx[w]) && (w == 1) )
{
LL = 1;
//cout << endl<<”ion is in layer “ << LL << endl;
break;
//break out of this For loop and go check if the particle is transmitted.
}
else if ( (Di.x <= xx[w]) && (Di.x > xx[w-1]) )
{
LL = w;
//cout << “ion is in layer “ << LL <<endl;
break; //break out of this For loop and go check if the particle is
transmitted.
}
}
//now, check for particle transmission, i.e. whether the particle went out of the
last layer.
if(Di.x >= xx[Layer])
{
//particle is transmitted, take care of appropriate variables and break
transmitted = 1;//cout << “ion number “ << ih << “ transmitted.” << endl;
it = it + 1;
et = et + e;
ia = 57.295779 * acos(cosin) / da + 1.0;
ie = 100 * e / e0 + 1.0;
//m[ie][ia] = m[ie][ia] + 1;//note: how is this possible? ie and ia should be
integers in order to access the elements of the array m[][]. But we calculate them as
doubles here!
break; //break out of the ‘mother’ do loop
}
//now take care of ionCounter and other variables for the next scattering
if(neighborFlag == 0)
{
if(ionCounter == 3)
{
//ionCounter = 0;
neighborFlag = 1;
scatterIonPos = ions[3];
//cout << endl << “got out of first two layers” << endl;
}
else
{
ionCounter++;
}
}
if(neighborFlag == 1)
{
//cout << “Updating Neighbor Ions” << endl;
neighborIonsBCC[0] = scatterIonPos + lx - ly + lz;
neighborIonsBCC[1] = scatterIonPos + lx + ly + lz;
neighborIonsBCC[2] = scatterIonPos + lx + ly - lz;
neighborIonsBCC[3] = scatterIonPos + lx - ly - lz;
neighborIonsBCC[4] = scatterIonPos + lx * 2;
neighborIonsBCC[5] = scatterIonPos - lx - ly - lz;
neighborIonsBCC[6] = scatterIonPos - lx + ly - lz;
neighborIonsBCC[7] = scatterIonPos - lx + ly + lz;
neighborIonsBCC[8] = scatterIonPos - lx - ly + lz;
neighborIonsBCC[9] = scatterIonPos + lz * 2;
neighborIonsBCC[10] = scatterIonPos - lz * 2;
neighborIonsBCC[11] = scatterIonPos + ly * 2;
neighborIonsBCC[12] = scatterIonPos - ly * 2;
neighborIonsBCC[13] = scatterIonPos - lx * 2;
}
//set DiPrev to Di
DiPrev = Di;
//update current lambda to lambdaPrime
lambda = lambdaPrime;
//now the while condition of the mother do loop checks if the particle has lesser
energy than our lowest energy limit, ef.
}
while(e > ef);
//since we are out of the mother do loop now, the particle must have come to a
stop. So, increase the final particle distributions if the particle has not been
transmitted or backscattered.
if( ((transmitted == 0)) && ((backscattered == 0)) && ((insideChannel == 1)) )
{
ip = (int)(pl/cw + 1.0);
if(ip > 100) ip = 100;
//ipl[ip] = ipl[ip] + 1;
xsum = xsum + Di.x;
//my own bin function
selectedXBin = whichBin(Di.x, xx[Layer], numXBin);
//write the selected bin to the output file
//outStream << selectedXBin << endl;
//cout << x << endl << xx[Layer] << endl << numXBin << endl << selectedXBin;
xBin[selectedXBin] = xBin[selectedXBin] + 1;
//print final x value for plotting histogram
//cout << “ion “ << ih << “ final x: “ << Di.x << endl;
infoStream << “ion “ << ih << “ final x: “ << Di.x << endl;
//cout << Di.x << “,”;
rangeStream << Di.x << endl;
plsum = plsum + pl;
icsum = icsum + ic;
//ipl is the ion path length - the total avg. distance the ion travels
regardless of direction before it comes to stop
}
//that brings us to the end of one ion’s journey, now go to next ion by going back
to the for loop’s beginning..
}
//and this ends the monte carlo loop function. Take care of necessary structures and
variables that need to be cleared/deleted
outStream.close();
scatterStream.close();
infoStream << “Number of Backscattered Ions: “ << ib << endl;
infoStream.close();
rangeStream.close();
}
int whichNonUniformBin(double e, double arr[], int numBins)
{
double low = 0, high = arr[0];
if((e>=low) && (e<high))
return 0;
else
{
for(int i = 0; i < numBins; i++)
{
low += arr[i];
high += arr[i+1];
//cout << “\tlow: “ << low << “, high:” << high << endl;
if((e>=low) && (e<high))
return i;
}
}
}
131
//============================================================================
// Name : monte.cpp
// Author : Nazmus Saquib
// Version :
// Copyright :
// Description : BCA code in C++
//============================================================================
#include “Globals.h”
#include “scoef.h”
#include “rstop.h”
#include “muscle_bca.h”
#include “vectorGeometry.h”
const int numXBin = 100;
const int numIons = 1;
int xBin[numXBin+1] = {0};
int selectedXBin = 0;
double rho[4]={0.0};
int n[]={0,0,0,0};
double e0kev, m1, cw, ed, latticeConst;
int z1, hn, iy, nowout;
double dx[3] = {0.0};
int zt[3][7] = {0};
double mt[3][7] = {0.};
double t[3][7] = {0.};
int Layer; //use this for number of layers rather than the L in the program;
//remember this cannot be set to 0. Other loops/arrays may start from
//0, but keep this >= 1;
//the arrays..
double my[3][7]= {0},
ai[3][7]= {0},
fi[3][7]= {0},
ec[3][7]= {0},
io[3][7]= {0},
k[3]= {0},
kl[3][7]= {0};
double vf[3][7]= {0},
mu[3]= {0},
ioniz[3]= {0},
h[3]= {0},
xx[3]= {0},
m2[3]= {0.0},
z2[3]= {0},
c[3]= {0},
epsbk[3]= {0},
arho[3]= {0};
double a[3]= {0},
f[3]= {0},
lm[3]= {0},
pmax[3]= {0},
fd[3]= {0},
kd[3]= {0},
sbk[3]= {0},
lf[3]= {0},
yy[8]= {0};
double se[3][1000]= {0.0},
seo[1000]= {0.0},
epsdg[3]= {0.0};
double ls = 0., lo = 0., maximum = 0.;
double xsum = 0, x2sum = 0, x3sum = 0, x4sum = 0, plsum = 0, pl2sum = 0;
double avex = 0, vari = 0, sigma = 0, v = 0, v2 = 0, Gamma = 0, beta = 0, y = 0, avepl
= 0, sigpl = 0, avecol = 0;
int i = 0, j = 0;
int ib = 0, it = 0;
double eb = 0.0, et = 0.0;
int icsum = 0;
double y2sum = 0, xy2sum = 0, x2y2su = 0, y4sum = 0;
double tau = 0;
int iii = -1;
//my dummy vars
int w; double q;
//my customized data structures or vars
scoefData scoefz1;
rstopData rstp;
//these vars (continuing from this line) are added later as needed, vars that were not
declared in the initialization of trim85 but showed up in the middle.
double e0, ef;
int iz;
double alfa, alpha;
double tmin, da;
double L0;
int iz1;
double ee;
int izt;
double nh;
double epso;
int ih;
double e;
//boolean for keeping track of a particle being transmitted or backscattered
int transmitted = 0;
int backscattered = 0;
//boolean for keeping track of channeling
int insideChannel = 1;
//boolean for determining whether to scatter from neighbor atoms
int neighborFlag = 0;
//main function
int main()
{
cout << “Initializing” << endl;
Initialize(“IronInput.dat”);
calculateAvgMassOfLayer();
getStoppingForTarget();
setInitialConditions();
MonteCarlo();
/* *********************** Testing Ground for arrays and variables
******************** */
for (w = 1; w <= 8; w++) cout << “\t “ << yy[w];
for (w = 1; w <= 3; w++) cout << “\n\t “ << xx[w];
cout << “CW or L0: “ << L0;
//(trouble! The values of n[] elements are changing like crazy)
cout << endl << n[0] << “\t” << n[1] << “\t” << n[2] << “\t” << n[3] << endl;
cout << endl << rho[0] << “\t” << rho[1] << “\t” << rho[2] << “\t” << rho[3] <<
“\t” << rho[4] << endl;
//test z2[], m2[] arrays
for (w = 1; w <= Layer; w++) cout << “\t “ << z2[w];
for (w = 1; w <= Layer; w++) cout << “\n\t “ << m2[w];
//test the se values
cout << endl << se[1][1000] << “ “ << se[2][1000] << “ “ << se[3][1000] << endl;
//test the se[] values by printing 10th element from the array (to be implemented)
//for (w = 1; w <= 100; w++)
//{
//for (int sss = 1; sss <= 50; sss++)
//{
//cout << “\t” << mpart[w][sss];
//}
//}
/* *********************** End of Testing Ground ************************** */
cout << endl;
//Now print values of each bin in xBin
//for (w = 1; w <= numXBin; w++) cout << xBin[w] << “,”;
//print final x values
cout << endl;
cout << “Number of Backscattered Ions: “ << ib << endl;
cout << “Number of Transmitted Ions: “ << it << endl;
return 0;
}
//end of main
//Helper functions follow from here
//initialize variables and setup each layer over here
void Initialize(char* filename)
{
//Read command file
ifstream instream;
instream.open(filename,ios::in);
cout << filename;
if (!instream)
{
exitOnError(filename);
}
instream >> e0kev >> z1 >> m1 >> latticeConst >> hn >> cw >> ed >> iy >> nowout;
instream >> dx[1] >> rho[1];
instream >> zt[1][1] >> mt[1][1] >> t[1][1];
instream >> n[1];
instream >> dx[2] >> rho[2];
instream >> zt[2][1] >> mt[2][1] >> t[2][1];
instream >> n[2];
instream >> dx[3] >> rho[3];
instream >> zt[3][1] >> mt[3][1] >> t[3][1];
instream >> n[3];
for (w = 0; w <= 3; w++)
{ if (n[w] != 1) n[w] = 1; }
instream.close();
Layer = 3;
//done with primary (crude) setup, off to reading scoef.dat file
iz = z1;
getstructScoef(iz, scoefz1, “scoef1.dat”); //used to get pcoef data yy in trim85
//so we put the values in yy here immediately
for (w = 1; w <= 8; w++)
{ yy[w] = scoefz1.pcoef[w]; }
//note: although yy turns out to be just a dummy array
e0 = e0kev*1000; //convert to ev.
if (ed == 0.) ed = 25.0;
ef = Max(5.0, e0kev*0.1);
//alfa = angle of incidence, alpha = radian of alfa
alfa = 0.;
alpha = alfa*Pi/180;
tmin = 5.0;
tau = 0.0;
da = 3.0;
if (iy == 0) iy = 16381;
//now calculate the total depth of each layer = xx(l), and grid spacing cw
xx[1] = dx[1];
for (w = 2; w <= 3; w++) { xx[w] = dx[w] + xx[w-1]; }
if (cw == 0) cw = 0.01*xx[3];
L0 = cw;
//take care of any custom variable or struct I made
rstp.vfermi = 0.0; //set this to 0. for the time being (see log for explanation)
//now, off to avg mass of layer in the next void function
}
//avg mass and atomic number of each layer
void calculateAvgMassOfLayer()
{
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
h[LL] = h[LL] + t[LL][w];
//cout << “testing here..” << rstp.vfermi << endl;
}
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
t[LL][w] = t[LL][w]/h[LL];
m2[LL] = m2[LL] + t[LL][w] * mt[LL][w];
z2[LL] = z2[LL] + t[LL][w] * zt[LL][w];
//note: z2 wont be an integer once t has a value other than 1.0??
//so are we calculating average atomic number here? why?
}
}
//done with this, off to finding electronic stopping powers in the next function
}
void getStoppingForTarget()
{
iz1 = z1; ee = 0;
for (int LL = 1; LL <= Layer; LL++)
{
arho[LL] = rho[LL] * 0.6022/(m2[LL]);
mu[LL] = m1/(m2[LL]);
int ii = n[LL];
for (int nn = 1; nn <= ii; nn++)
{
//set rstp.se[1..1000] = 0. Clear it for the next loop
for (w = 1; w <= 1000; w++)
{ rstp.se[w] = 0.; }
izt = zt[LL][nn];
//calling getrstop now. units, lfctr, vfermi = 1 (doesnt matter)
getrStop(iz1, izt, e0kev, 1, 1., 1., rstp); //rstp defined in header
//set this anyway, though I dont calculate this in RSTOP
vf[LL][nn] = rstp.vfermi; //which is just set 0 in the struct def.
for (w = 1; w <= 1000; w++)
{
se[LL][w] = se[LL][w] + rstp.se[w] * t[LL][nn] * arho[LL];
}
}
}
//now, off to setting up initial conditions next function
}
void setInitialConditions()
{
nh = hn; //number of histories
for (int LL = 1; LL <= Layer; LL++)
{
a[LL] = 0.5292 * 0.8853 / ( pow(z1, 0.23) + pow(z2[LL], 0.23) );
//now calculate the mean flight path with the conditions given in trim85
f[LL] = a[LL] * m2[LL] / ( z1 * z2[LL] * 14.4 * (m1 + m2[LL] ) );
epso = e0 * f[LL];
epsdg[LL] = tmin * f[LL] * pow( (1.0 + mu[LL]) , 2) / (4.0 * mu[LL]);
fd[LL] = 0.01 * pow( z2[LL], (-7.0/3.0) );
kd[LL] = 0.1334 * pow ( z2[LL], (2.0/3.0) ) / sqrt( m2[LL] );
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
my[LL][w] = m1/mt[LL][w];
ec[LL][w] = 4.0 * my[LL][w] / pow( ( 1.0 + my[LL][w] ), 2);
ai[LL][w] = 0.5292 * 0.8853 / ( pow(z1,0.23) + pow(zt[LL][w],0.23) );
fi[LL][w] = ai[LL][w] * mt[LL][w] / ( z1 * zt[LL][w] * 14.4 * ( m1 + mt[LL][w] ) );
}
}
cout << “Setup finished. Starting Monte Carlo Loops..”;
//off to monte carlo loop in next routine
}
void MonteCarlo()
{
//custom variables and arrays for this section
double e;
double cosin = 0.0, siny = 0.0, sine = 0.0, cosy = 0.0;
double pl = 0.0;
int ic;
int LL = 1;
double eps;
double eeg;
double p;
double b;
int ie, ia; //not sure if ie or ia should be double. They are used to access elements
of the m[][] array at some point
double see;
double dee;
double s2, c2, ct, st;
double r, rr;
double ex1, ex2, ex3, ex4;
double v, v1;
double fr, fr1;
double q;
double roc, sqe;
double cc, aa, ff;
double delta, co;
double den;
double phi, psi;
double x1;
int ip;
//variables for crystal calculations
double sep = 0.0;
int ionCounter = 0;
double p1, p2;
double Theta = 0.0;
double rTheta = 0.0, rPhi = 0.0;
double thetaThreshold = 0.5;
double crystalMuonY = 0.0, crystalMuonZ = 0.0;
//amount of translations in y and z axes
double translationY = 0.0, translationZ = 0.0;
//Scatter Plot variables
const int numScatterPlotBins = 5;
double scatterPlot[numScatterPlotBins + 1] = {0.0};
//Vector declarations
//lattice constant of Target (input from file)
double latticeConstant = latticeConst;
Vector3 ions[4];
Vector3 ionsOrdered[4];
Vector3 neighborIonsBCC[14];
Vector3 neighborIonsFCC[14];
Vector3 ionTranslationY(0,translationY,0);
Vector3 ionTranslationZ(0,0,translationZ);
Vector3 unitzplus, unitzminus, unityplus, unityminus, unitxplus, unitxminus;
unitzplus.z = 1;
unitzminus.z = -1;
unityplus.y = 1;
unityminus.y = -1;
unitxplus.x = 1;
unitxminus.x = -1;
Vector3 initialDirection(1,0,0);
Vector3 d;
d.x = 1;
d *= latticeConstant/2;
Vector3 lx(latticeConstant/2, 0, 0);
Vector3 ly(0, latticeConstant/2, 0);
Vector3 lz(0, 0, latticeConstant/2);
Vector3 lambda;
Vector3 lambdaPrime;
Vector3 pVector;
Vector3 pUnitVector;
Vector3 sepVector;
Vector3 Di;
Vector3 DiPrev;
//Vector3 DiPrevToDi;
Vector3 delX;
Vector3 delX1, delX2;
Vector3 dummy1, dummy2, temp;
Vector3 scatterIonPos;
//initialize the random number generator
srand(time(NULL));
//open file to write output
ofstream outStream;
outStream.open(“coords0.txt”);
if(outStream.fail())
{
exitOnError(“Could not open Output file”);
}
//write basic information in the output file
//number of ions, ion energy, total depth, depth of each layer
outStream << nh << “\t” << e0kev << “\t” << xx[Layer] << “\t” << dx[1] << “\t”
<< dx[2] << “\t” << dx[3] << endl;
//open scatter plot file to write current Y and Z coordinates of muons at designated
intervals
ofstream scatterStream;
scatterStream.open(“scatterOut1.txt”);
if(scatterStream.fail())
{
exitOnError(“Could not open Scatter Plot Output file”);
}
//open range distribution file to write final X coordinates of muons
ofstream rangeStream;
rangeStream.open(“rangeOut1.txt”);
if(rangeStream.fail())
{
exitOnError(“Could not open Range Distribution Output file”);
}
//Open general information dump file
ofstream infoStream;
infoStream.open(“info1.txt”);
if(infoStream.fail())
{
exitOnError(“Could not open general information Output file”);
}
//Entering the target
//First set up for the top layer
for (ih = 1; ih <= nh; ih++)
{
avex = xsum / Max(1.0, (float)(ih - ib - it - 1));
if (talk == 2) cout << “Average ion range so far: “ << avex << “ angstroms.”
<<endl;
if (talk > 2) cout << “Now starting ion number “ << ih << endl;
e = e0;
//set scatterPlot array (the intervals)
scatterPlot[0] = 10;
scatterPlot[1] = 30;
scatterPlot[2] = 50;
scatterPlot[3] = 100;
scatterPlot[4] = 150;
scatterPlot[5] = 200;
/*
for(int ccc = 0; ccc <= numScatterPlotBins; ccc++)
{
cout << “scatter plot “ << ccc << “: “ << scatterPlot[ccc] << endl;
}
*/
//Initial Ion Positions
ions[0] = d + ionTranslationZ + unitzminus * (latticeConstant/2);
ions[1] = d + ionTranslationZ + unitzplus * (latticeConstant/2);
ions[2] = d * 2 + ionTranslationY + unityminus * (latticeConstant/2);
ions[3] = d * 2 + ionTranslationY + unityplus * (latticeConstant/2);
//Create a polygon that resides on the lateral axes.
//The points are put on anticlockwise order, which is important for
//testing whether the test point lies on this polygon
ionsOrdered[0] = ions[0];
ionsOrdered[1] = ions[2];
ionsOrdered[2] = ions[1];
ionsOrdered[3] = ions[3];
//generate random theta and phi angles.
rTheta = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * thetaThreshold;
rPhi = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * 2 * Pi;
//find corresponding x, y and z components of the direction vector.
//radius of the direction vector is 1
initialDirection.x = cos(rTheta);
initialDirection.z = sin(rTheta) * cos(rPhi);
initialDirection.y = sin(rTheta) * sin(rPhi);
//set the counter to 0 for a new ion
ionCounter = 0;
pl = 0.0;
ic = 0;
//set initial DiPrev - the origin
DiPrev.x = 0.0; DiPrev.y = 0.0; DiPrev.z = 0.0;
//set initial lambda, the direction of motion. Normalize it.
lambda.clear();
lambda = initialDirection;
lambda.normalize();
//set initial delX to origin
delX.clear();
//clear the dummy delX vectors, set them to origin
delX1.clear();
delX2.clear();
dummy1.clear();
dummy2.clear();
temp.clear();
LL = 1;
//set transmitted and backscattered to false
transmitted = 0;
backscattered = 0;
//set channeling to true
insideChannel = 1;
neighborFlag = 0;
//write the initial coordinates to the output file
outStream << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << endl << “Initial: “;
//cout << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << “r1 = “ << r1 << endl;
//cycle for each collision until the energy of the particle becomes too low, or
the particle backscatters, or it goes out of the last layer (transmission)
//needs a do while loop here,
//which I will mention as the ‘mother loop’ from now.
do
{
ic = ic + 1;
eps = e * f[LL];
eeg = sqrt(eps*epsdg[LL]);
//pmax[LL] = a[LL] / (eeg + sqrt(eeg) + 0.125 * pow( eeg, 0.1) );
pmax[LL] = sqrt(3) * (latticeConstant / 2) * 0.7;
//Calculate impact parameter and choose the atom to scatter from.
//Do this for ion pairs 0,1 and 2,3.
if (ionCounter == 0)
{
delX1 = ions[0] - DiPrev;
delX2 = ions[1] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[0];
ions[0] = ions[1];
ions[1] = temp;
//cout << “Vertical Ions swapped” << endl;
}
}
if (ionCounter == 2)
{
delX1 = ions[2] - DiPrev;
delX2 = ions[3] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[2];
ions[2] = ions[3];
ions[3] = temp;
//cout << “Horizontal Ions swapped” << endl;
}
}
//now calculate impact parameter
if(neighborFlag == 0)
{
delX = ions[ionCounter] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
else if(neighborFlag == 1)
{
double impact[13] = {0.0};
double radial[13] = {0.0};
double S[13] = {0.0};
double sumS = 0.0;
double Probability[13] = {0.0};
double rnd_candidate = 0.0;
int selected_candidate = -1;
for(int ncount = 0; ncount <= 13; ncount++)
{
delX = neighborIonsBCC[ncount] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
//scatterIonPos = neighborIonsBCC[ncount];
impact[ncount] = p;
radial[ncount] = delX.magnitude();
S[ncount] = 1 / ( pow(impact[ncount],2) * radial[ncount] );
sumS += S[ncount];
//general scheme of selecting the neighbor ion
// if(p < pmax[LL])
// {
// scatterIonPos = neighborIonsBCC[ncount];
// //cout << “Neighbor “ << ncount << “ is selected” << endl;
// break;
// }
}
for(int ncount = 0; ncount <= 13; ncount++)
{
Probability[ncount] = S[ncount] / sumS;
}
//print out the probability array
cout << endl;
for(int ncount = 0; ncount <= 13; ncount++)
{
//cout << Probability[ncount] << “ “;
infoStream << Probability[ncount] << “ “;
}
infoStream << endl;
//cout << endl;
//random number between 0 and 1
rnd_candidate = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) );
//cout << “rand_candidate: “ << rnd_candidate << endl;
//choose the candidate for scattering
selected_candidate = whichNonUniformBin(rnd_candidate, Probability, 13);
//cout << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate <<
endl;
infoStream << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate
<< endl;
//assign the scatterIonPos variable to the selected neighbor
scatterIonPos = neighborIonsBCC[selected_candidate];
//cout << “Scattering Ion Position: “; scatterIonPos.printVector();
//find the essential quantities for the selected neighbor
delX = neighborIonsBCC[selected_candidate] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
//find eps and b using fi[LL][nn], using nn that I was supposed to find from above
//here im deliberately using nn = 1
eps = fi[LL][1] * e;
b = p / ai[LL][1];
if (eps > 10) //rutherford scattering
{
s2 = 1.0 / (1.0 + (1.0 + b * (1.0 + b)) * pow((2.0 * eps * b), 2) );
c2 = 1.0 - s2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
else //magic formula
{
r = b;
rr = -2.7 * log(eps * b);
if (rr >= b)//note >= sign instead < in trim85
{
rr = -2.7 * log(eps * rr);
if (rr >= b)//note >= sign instead < in trim85
{
r = rr;
}
}
//do while loop that replaces line 330 loop
do
{
ex1 = 0.18175 * exp(-3.1998 * r);
ex2 = 0.50986 * exp(-0.94229 * r);
ex3 = 0.28022 * exp(-0.4029 * r);
ex4 = 0.028171 * exp(-0.20162 * r);
v = (ex1 + ex2 + ex3 + ex4) / r;
v1 = -(v + 3.1998 * ex1 + 0.94229 * ex2 + 0.4029 * ex3 + 0.20162 * ex4) / r;
fr = b * b / r + v * r / eps - r;
fr1 = -b * b / (r * r) + (v + v1 * r) / eps - 1.0;
q = fr / fr1;
r = r - q;
}
while( (Abs(q / r)) > 0.001 );
roc = -2.0 * (eps - v) / v1;
sqe = sqrt(eps);
//5 parameter magic scattering calculation
//below is for universal potential
cc = (0.011615 + sqe) / (0.0071222 + sqe);
aa = 2.0 * eps * (1.0 + (0.99229 / sqe) ) * ( pow(b, cc) );
ff = ( sqrt(aa * aa + 1.0) - aa) * ( (9.3066 + eps) / (14.813 + eps) );
delta = (r - b) * aa * ff / (ff + 1.0);
co = (b + delta + roc) / (r + roc);
c2 = co * co;
s2 = 1.0 - c2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
Theta = acos(ct);
//we are done finding theta (in CM system). So calculate all other quantities.
//find separation and the separation vector.
phi = (Pi - Theta) / 2;
sep = p / tan(phi);
sepVector = lambda * sep;
//find theta in laboratory frame - psi
psi = atan(st / (ct + my[LL][1] ) );
//note: change my[LL][1] to my[LL][nn] when the above section is fixed.
if (psi < 0 ) psi = psi + Pi; //should I do this for crystals?
//find Di, the scattering point vector
Di = DiPrev + delX + pVector - sepVector;
//find new direction of motion
lambdaPrime = lambda * cos(psi) + pUnitVector * sin(psi);
lambdaPrime.normalize();
//find length of step, ls = distance of Di from DiPrev
ls = Di.getDistance(DiPrev);
//find energy lost due to electronic stopping, dee
ie = (int)(e/e0kev+0.5); //should it be 0.5? or less so that ie <=1000?
see = se[LL][ie];
if (e < e0kev) see = se[LL][1] * sqrt(e/e0kev);
dee = ls * see;
// den = energy transferred to recoil
den = ec[LL][1] * s2 * e; //note: I am using ec[LL][1] here instead of [LL][nn].
//cout << “den = “ << den << “, dee = “ << dee << endl;
infoStream << “den = “ << den << “, dee = “ << dee << endl;
e = e - den - dee;
//cout << endl<< “current ion energy: “ << e << endl;
if (dee > maximum) maximum = dee;
pl = pl + ls - tau;
//write the ion position to output file
outStream << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
if((ic%30)==0)
{
//cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
}
//determine which scatter plot Di’s x value belongs to.
//output the y and z coordinates to scatter plot file accordingly.
for(int cc = 0; cc <= numScatterPlotBins; cc++)
{
if( Di.x >= (scatterPlot[cc]) )
{
crystalMuonY = Di.y - translationY;
crystalMuonZ = Di.z - translationZ;
//cout << “scatter plot “ << ct << “: “ << scatterPlot[ct] << endl;
scatterStream << scatterPlot[cc] << “\t” << crystalMuonY << “\t” <<
crystalMuonZ << endl;
//set scatterPlot[ss] to a big number
scatterPlot[cc] = 10000;
//break out of this for loop
break;
}
}
//determine if Di is in the channeling region.
//insideChannel = Di.isInsidePolygon(ionsOrdered, 4);
//break out of parent loop if not inside the channel
if(insideChannel == 0)
{
cout << “Ion “ << ih << “ is out of Channel” << endl;
cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
break;
}
//determine which layer the next collision will be in
if (Di.x < 0.0) //particle is backscattered
{
backscattered = 1; //cout << “ion number “ << ih << “ backscattered.” << endl;
infoStream << “ion number “ << ih << “ backscattered.” << endl;
ib = ib + 1;
eb = eb + e;
break; //break out of ‘mother do loop’ and continue with the next session of
for loop.
}
//here we set the current or next layer the particle will be in
for (w = 1; w <= Layer; w++)
{
if ( (Di.x <= xx[w]) && (w == 1) )
{
LL = 1;
//cout << endl<<”ion is in layer “ << LL << endl;
break;
//break out of this For loop and go check if the particle is transmitted.
}
else if ( (Di.x <= xx[w]) && (Di.x > xx[w-1]) )
{
LL = w;
//cout << “ion is in layer “ << LL <<endl;
break; //break out of this For loop and go check if the particle is
transmitted.
}
}
//now, check for particle transmission, i.e. whether the particle went out of the
last layer.
if(Di.x >= xx[Layer])
{
//particle is transmitted, take care of appropriate variables and break
transmitted = 1;//cout << “ion number “ << ih << “ transmitted.” << endl;
it = it + 1;
et = et + e;
ia = 57.295779 * acos(cosin) / da + 1.0;
ie = 100 * e / e0 + 1.0;
//m[ie][ia] = m[ie][ia] + 1;//note: how is this possible? ie and ia should be
integers in order to access the elements of the array m[][]. But we calculate them as
doubles here!
break; //break out of the ‘mother’ do loop
}
//now take care of ionCounter and other variables for the next scattering
if(neighborFlag == 0)
{
if(ionCounter == 3)
{
//ionCounter = 0;
neighborFlag = 1;
scatterIonPos = ions[3];
//cout << endl << “got out of first two layers” << endl;
}
else
{
ionCounter++;
}
}
if(neighborFlag == 1)
{
//cout << “Updating Neighbor Ions” << endl;
neighborIonsBCC[0] = scatterIonPos + lx - ly + lz;
neighborIonsBCC[1] = scatterIonPos + lx + ly + lz;
neighborIonsBCC[2] = scatterIonPos + lx + ly - lz;
neighborIonsBCC[3] = scatterIonPos + lx - ly - lz;
neighborIonsBCC[4] = scatterIonPos + lx * 2;
neighborIonsBCC[5] = scatterIonPos - lx - ly - lz;
neighborIonsBCC[6] = scatterIonPos - lx + ly - lz;
neighborIonsBCC[7] = scatterIonPos - lx + ly + lz;
neighborIonsBCC[8] = scatterIonPos - lx - ly + lz;
neighborIonsBCC[9] = scatterIonPos + lz * 2;
neighborIonsBCC[10] = scatterIonPos - lz * 2;
neighborIonsBCC[11] = scatterIonPos + ly * 2;
neighborIonsBCC[12] = scatterIonPos - ly * 2;
neighborIonsBCC[13] = scatterIonPos - lx * 2;
}
//set DiPrev to Di
DiPrev = Di;
//update current lambda to lambdaPrime
lambda = lambdaPrime;
//now the while condition of the mother do loop checks if the particle has lesser
energy than our lowest energy limit, ef.
}
while(e > ef);
//since we are out of the mother do loop now, the particle must have come to a
stop. So, increase the final particle distributions if the particle has not been
transmitted or backscattered.
if( ((transmitted == 0)) && ((backscattered == 0)) && ((insideChannel == 1)) )
{
ip = (int)(pl/cw + 1.0);
if(ip > 100) ip = 100;
//ipl[ip] = ipl[ip] + 1;
xsum = xsum + Di.x;
//my own bin function
selectedXBin = whichBin(Di.x, xx[Layer], numXBin);
//write the selected bin to the output file
//outStream << selectedXBin << endl;
//cout << x << endl << xx[Layer] << endl << numXBin << endl << selectedXBin;
xBin[selectedXBin] = xBin[selectedXBin] + 1;
//print final x value for plotting histogram
//cout << “ion “ << ih << “ final x: “ << Di.x << endl;
infoStream << “ion “ << ih << “ final x: “ << Di.x << endl;
//cout << Di.x << “,”;
rangeStream << Di.x << endl;
plsum = plsum + pl;
icsum = icsum + ic;
//ipl is the ion path length - the total avg. distance the ion travels
regardless of direction before it comes to stop
}
//that brings us to the end of one ion’s journey, now go to next ion by going back
to the for loop’s beginning..
}
//and this ends the monte carlo loop function. Take care of necessary structures and
variables that need to be cleared/deleted
outStream.close();
scatterStream.close();
infoStream << “Number of Backscattered Ions: “ << ib << endl;
infoStream.close();
rangeStream.close();
}
int whichNonUniformBin(double e, double arr[], int numBins)
{
double low = 0, high = arr[0];
if((e>=low) && (e<high))
return 0;
else
{
for(int i = 0; i < numBins; i++)
{
low += arr[i];
high += arr[i+1];
//cout << “\tlow: “ << low << “, high:” << high << endl;
if((e>=low) && (e<high))
return i;
}
}
}
132
//============================================================================
// Name : monte.cpp
// Author : Nazmus Saquib
// Version :
// Copyright :
// Description : BCA code in C++
//============================================================================
#include “Globals.h”
#include “scoef.h”
#include “rstop.h”
#include “muscle_bca.h”
#include “vectorGeometry.h”
const int numXBin = 100;
const int numIons = 1;
int xBin[numXBin+1] = {0};
int selectedXBin = 0;
double rho[4]={0.0};
int n[]={0,0,0,0};
double e0kev, m1, cw, ed, latticeConst;
int z1, hn, iy, nowout;
double dx[3] = {0.0};
int zt[3][7] = {0};
double mt[3][7] = {0.};
double t[3][7] = {0.};
int Layer; //use this for number of layers rather than the L in the program;
//remember this cannot be set to 0. Other loops/arrays may start from
//0, but keep this >= 1;
//the arrays..
double my[3][7]= {0},
ai[3][7]= {0},
fi[3][7]= {0},
ec[3][7]= {0},
io[3][7]= {0},
k[3]= {0},
kl[3][7]= {0};
double vf[3][7]= {0},
mu[3]= {0},
ioniz[3]= {0},
h[3]= {0},
xx[3]= {0},
m2[3]= {0.0},
z2[3]= {0},
c[3]= {0},
epsbk[3]= {0},
arho[3]= {0};
double a[3]= {0},
f[3]= {0},
lm[3]= {0},
pmax[3]= {0},
fd[3]= {0},
kd[3]= {0},
sbk[3]= {0},
lf[3]= {0},
yy[8]= {0};
double se[3][1000]= {0.0},
seo[1000]= {0.0},
epsdg[3]= {0.0};
double ls = 0., lo = 0., maximum = 0.;
double xsum = 0, x2sum = 0, x3sum = 0, x4sum = 0, plsum = 0, pl2sum = 0;
double avex = 0, vari = 0, sigma = 0, v = 0, v2 = 0, Gamma = 0, beta = 0, y = 0, avepl
= 0, sigpl = 0, avecol = 0;
int i = 0, j = 0;
int ib = 0, it = 0;
double eb = 0.0, et = 0.0;
int icsum = 0;
double y2sum = 0, xy2sum = 0, x2y2su = 0, y4sum = 0;
double tau = 0;
int iii = -1;
//my dummy vars
int w; double q;
//my customized data structures or vars
scoefData scoefz1;
rstopData rstp;
//these vars (continuing from this line) are added later as needed, vars that were not
declared in the initialization of trim85 but showed up in the middle.
double e0, ef;
int iz;
double alfa, alpha;
double tmin, da;
double L0;
int iz1;
double ee;
int izt;
double nh;
double epso;
int ih;
double e;
//boolean for keeping track of a particle being transmitted or backscattered
int transmitted = 0;
int backscattered = 0;
//boolean for keeping track of channeling
int insideChannel = 1;
//boolean for determining whether to scatter from neighbor atoms
int neighborFlag = 0;
//main function
int main()
{
cout << “Initializing” << endl;
Initialize(“IronInput.dat”);
calculateAvgMassOfLayer();
getStoppingForTarget();
setInitialConditions();
MonteCarlo();
/* *********************** Testing Ground for arrays and variables
******************** */
for (w = 1; w <= 8; w++) cout << “\t “ << yy[w];
for (w = 1; w <= 3; w++) cout << “\n\t “ << xx[w];
cout << “CW or L0: “ << L0;
//(trouble! The values of n[] elements are changing like crazy)
cout << endl << n[0] << “\t” << n[1] << “\t” << n[2] << “\t” << n[3] << endl;
cout << endl << rho[0] << “\t” << rho[1] << “\t” << rho[2] << “\t” << rho[3] <<
“\t” << rho[4] << endl;
//test z2[], m2[] arrays
for (w = 1; w <= Layer; w++) cout << “\t “ << z2[w];
for (w = 1; w <= Layer; w++) cout << “\n\t “ << m2[w];
//test the se values
cout << endl << se[1][1000] << “ “ << se[2][1000] << “ “ << se[3][1000] << endl;
//test the se[] values by printing 10th element from the array (to be implemented)
//for (w = 1; w <= 100; w++)
//{
//for (int sss = 1; sss <= 50; sss++)
//{
//cout << “\t” << mpart[w][sss];
//}
//}
/* *********************** End of Testing Ground ************************** */
cout << endl;
//Now print values of each bin in xBin
//for (w = 1; w <= numXBin; w++) cout << xBin[w] << “,”;
//print final x values
cout << endl;
cout << “Number of Backscattered Ions: “ << ib << endl;
cout << “Number of Transmitted Ions: “ << it << endl;
return 0;
}
//end of main
//Helper functions follow from here
//initialize variables and setup each layer over here
void Initialize(char* filename)
{
//Read command file
ifstream instream;
instream.open(filename,ios::in);
cout << filename;
if (!instream)
{
exitOnError(filename);
}
instream >> e0kev >> z1 >> m1 >> latticeConst >> hn >> cw >> ed >> iy >> nowout;
instream >> dx[1] >> rho[1];
instream >> zt[1][1] >> mt[1][1] >> t[1][1];
instream >> n[1];
instream >> dx[2] >> rho[2];
instream >> zt[2][1] >> mt[2][1] >> t[2][1];
instream >> n[2];
instream >> dx[3] >> rho[3];
instream >> zt[3][1] >> mt[3][1] >> t[3][1];
instream >> n[3];
for (w = 0; w <= 3; w++)
{ if (n[w] != 1) n[w] = 1; }
instream.close();
Layer = 3;
//done with primary (crude) setup, off to reading scoef.dat file
iz = z1;
getstructScoef(iz, scoefz1, “scoef1.dat”); //used to get pcoef data yy in trim85
//so we put the values in yy here immediately
for (w = 1; w <= 8; w++)
{ yy[w] = scoefz1.pcoef[w]; }
//note: although yy turns out to be just a dummy array
e0 = e0kev*1000; //convert to ev.
if (ed == 0.) ed = 25.0;
ef = Max(5.0, e0kev*0.1);
//alfa = angle of incidence, alpha = radian of alfa
alfa = 0.;
alpha = alfa*Pi/180;
tmin = 5.0;
tau = 0.0;
da = 3.0;
if (iy == 0) iy = 16381;
//now calculate the total depth of each layer = xx(l), and grid spacing cw
xx[1] = dx[1];
for (w = 2; w <= 3; w++) { xx[w] = dx[w] + xx[w-1]; }
if (cw == 0) cw = 0.01*xx[3];
L0 = cw;
//take care of any custom variable or struct I made
rstp.vfermi = 0.0; //set this to 0. for the time being (see log for explanation)
//now, off to avg mass of layer in the next void function
}
//avg mass and atomic number of each layer
void calculateAvgMassOfLayer()
{
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
h[LL] = h[LL] + t[LL][w];
//cout << “testing here..” << rstp.vfermi << endl;
}
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
t[LL][w] = t[LL][w]/h[LL];
m2[LL] = m2[LL] + t[LL][w] * mt[LL][w];
z2[LL] = z2[LL] + t[LL][w] * zt[LL][w];
//note: z2 wont be an integer once t has a value other than 1.0??
//so are we calculating average atomic number here? why?
}
}
//done with this, off to finding electronic stopping powers in the next function
}
void getStoppingForTarget()
{
iz1 = z1; ee = 0;
for (int LL = 1; LL <= Layer; LL++)
{
arho[LL] = rho[LL] * 0.6022/(m2[LL]);
mu[LL] = m1/(m2[LL]);
int ii = n[LL];
for (int nn = 1; nn <= ii; nn++)
{
//set rstp.se[1..1000] = 0. Clear it for the next loop
for (w = 1; w <= 1000; w++)
{ rstp.se[w] = 0.; }
izt = zt[LL][nn];
//calling getrstop now. units, lfctr, vfermi = 1 (doesnt matter)
getrStop(iz1, izt, e0kev, 1, 1., 1., rstp); //rstp defined in header
//set this anyway, though I dont calculate this in RSTOP
vf[LL][nn] = rstp.vfermi; //which is just set 0 in the struct def.
for (w = 1; w <= 1000; w++)
{
se[LL][w] = se[LL][w] + rstp.se[w] * t[LL][nn] * arho[LL];
}
}
}
//now, off to setting up initial conditions next function
}
void setInitialConditions()
{
nh = hn; //number of histories
for (int LL = 1; LL <= Layer; LL++)
{
a[LL] = 0.5292 * 0.8853 / ( pow(z1, 0.23) + pow(z2[LL], 0.23) );
//now calculate the mean flight path with the conditions given in trim85
f[LL] = a[LL] * m2[LL] / ( z1 * z2[LL] * 14.4 * (m1 + m2[LL] ) );
epso = e0 * f[LL];
epsdg[LL] = tmin * f[LL] * pow( (1.0 + mu[LL]) , 2) / (4.0 * mu[LL]);
fd[LL] = 0.01 * pow( z2[LL], (-7.0/3.0) );
kd[LL] = 0.1334 * pow ( z2[LL], (2.0/3.0) ) / sqrt( m2[LL] );
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
my[LL][w] = m1/mt[LL][w];
ec[LL][w] = 4.0 * my[LL][w] / pow( ( 1.0 + my[LL][w] ), 2);
ai[LL][w] = 0.5292 * 0.8853 / ( pow(z1,0.23) + pow(zt[LL][w],0.23) );
fi[LL][w] = ai[LL][w] * mt[LL][w] / ( z1 * zt[LL][w] * 14.4 * ( m1 + mt[LL][w] ) );
}
}
cout << “Setup finished. Starting Monte Carlo Loops..”;
//off to monte carlo loop in next routine
}
void MonteCarlo()
{
//custom variables and arrays for this section
double e;
double cosin = 0.0, siny = 0.0, sine = 0.0, cosy = 0.0;
double pl = 0.0;
int ic;
int LL = 1;
double eps;
double eeg;
double p;
double b;
int ie, ia; //not sure if ie or ia should be double. They are used to access elements
of the m[][] array at some point
double see;
double dee;
double s2, c2, ct, st;
double r, rr;
double ex1, ex2, ex3, ex4;
double v, v1;
double fr, fr1;
double q;
double roc, sqe;
double cc, aa, ff;
double delta, co;
double den;
double phi, psi;
double x1;
int ip;
//variables for crystal calculations
double sep = 0.0;
int ionCounter = 0;
double p1, p2;
double Theta = 0.0;
double rTheta = 0.0, rPhi = 0.0;
double thetaThreshold = 0.5;
double crystalMuonY = 0.0, crystalMuonZ = 0.0;
//amount of translations in y and z axes
double translationY = 0.0, translationZ = 0.0;
//Scatter Plot variables
const int numScatterPlotBins = 5;
double scatterPlot[numScatterPlotBins + 1] = {0.0};
//Vector declarations
//lattice constant of Target (input from file)
double latticeConstant = latticeConst;
Vector3 ions[4];
Vector3 ionsOrdered[4];
Vector3 neighborIonsBCC[14];
Vector3 neighborIonsFCC[14];
Vector3 ionTranslationY(0,translationY,0);
Vector3 ionTranslationZ(0,0,translationZ);
Vector3 unitzplus, unitzminus, unityplus, unityminus, unitxplus, unitxminus;
unitzplus.z = 1;
unitzminus.z = -1;
unityplus.y = 1;
unityminus.y = -1;
unitxplus.x = 1;
unitxminus.x = -1;
Vector3 initialDirection(1,0,0);
Vector3 d;
d.x = 1;
d *= latticeConstant/2;
Vector3 lx(latticeConstant/2, 0, 0);
Vector3 ly(0, latticeConstant/2, 0);
Vector3 lz(0, 0, latticeConstant/2);
Vector3 lambda;
Vector3 lambdaPrime;
Vector3 pVector;
Vector3 pUnitVector;
Vector3 sepVector;
Vector3 Di;
Vector3 DiPrev;
//Vector3 DiPrevToDi;
Vector3 delX;
Vector3 delX1, delX2;
Vector3 dummy1, dummy2, temp;
Vector3 scatterIonPos;
//initialize the random number generator
srand(time(NULL));
//open file to write output
ofstream outStream;
outStream.open(“coords0.txt”);
if(outStream.fail())
{
exitOnError(“Could not open Output file”);
}
//write basic information in the output file
//number of ions, ion energy, total depth, depth of each layer
outStream << nh << “\t” << e0kev << “\t” << xx[Layer] << “\t” << dx[1] << “\t”
<< dx[2] << “\t” << dx[3] << endl;
//open scatter plot file to write current Y and Z coordinates of muons at designated
intervals
ofstream scatterStream;
scatterStream.open(“scatterOut1.txt”);
if(scatterStream.fail())
{
exitOnError(“Could not open Scatter Plot Output file”);
}
//open range distribution file to write final X coordinates of muons
ofstream rangeStream;
rangeStream.open(“rangeOut1.txt”);
if(rangeStream.fail())
{
exitOnError(“Could not open Range Distribution Output file”);
}
//Open general information dump file
ofstream infoStream;
infoStream.open(“info1.txt”);
if(infoStream.fail())
{
exitOnError(“Could not open general information Output file”);
}
//Entering the target
//First set up for the top layer
for (ih = 1; ih <= nh; ih++)
{
avex = xsum / Max(1.0, (float)(ih - ib - it - 1));
if (talk == 2) cout << “Average ion range so far: “ << avex << “ angstroms.”
<<endl;
if (talk > 2) cout << “Now starting ion number “ << ih << endl;
e = e0;
//set scatterPlot array (the intervals)
scatterPlot[0] = 10;
scatterPlot[1] = 30;
scatterPlot[2] = 50;
scatterPlot[3] = 100;
scatterPlot[4] = 150;
scatterPlot[5] = 200;
/*
for(int ccc = 0; ccc <= numScatterPlotBins; ccc++)
{
cout << “scatter plot “ << ccc << “: “ << scatterPlot[ccc] << endl;
}
*/
//Initial Ion Positions
ions[0] = d + ionTranslationZ + unitzminus * (latticeConstant/2);
ions[1] = d + ionTranslationZ + unitzplus * (latticeConstant/2);
ions[2] = d * 2 + ionTranslationY + unityminus * (latticeConstant/2);
ions[3] = d * 2 + ionTranslationY + unityplus * (latticeConstant/2);
//Create a polygon that resides on the lateral axes.
//The points are put on anticlockwise order, which is important for
//testing whether the test point lies on this polygon
ionsOrdered[0] = ions[0];
ionsOrdered[1] = ions[2];
ionsOrdered[2] = ions[1];
ionsOrdered[3] = ions[3];
//generate random theta and phi angles.
rTheta = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * thetaThreshold;
rPhi = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * 2 * Pi;
//find corresponding x, y and z components of the direction vector.
//radius of the direction vector is 1
initialDirection.x = cos(rTheta);
initialDirection.z = sin(rTheta) * cos(rPhi);
initialDirection.y = sin(rTheta) * sin(rPhi);
//set the counter to 0 for a new ion
ionCounter = 0;
pl = 0.0;
ic = 0;
//set initial DiPrev - the origin
DiPrev.x = 0.0; DiPrev.y = 0.0; DiPrev.z = 0.0;
//set initial lambda, the direction of motion. Normalize it.
lambda.clear();
lambda = initialDirection;
lambda.normalize();
//set initial delX to origin
delX.clear();
//clear the dummy delX vectors, set them to origin
delX1.clear();
delX2.clear();
dummy1.clear();
dummy2.clear();
temp.clear();
LL = 1;
//set transmitted and backscattered to false
transmitted = 0;
backscattered = 0;
//set channeling to true
insideChannel = 1;
neighborFlag = 0;
//write the initial coordinates to the output file
outStream << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << endl << “Initial: “;
//cout << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << “r1 = “ << r1 << endl;
//cycle for each collision until the energy of the particle becomes too low, or
the particle backscatters, or it goes out of the last layer (transmission)
//needs a do while loop here,
//which I will mention as the ‘mother loop’ from now.
do
{
ic = ic + 1;
eps = e * f[LL];
eeg = sqrt(eps*epsdg[LL]);
//pmax[LL] = a[LL] / (eeg + sqrt(eeg) + 0.125 * pow( eeg, 0.1) );
pmax[LL] = sqrt(3) * (latticeConstant / 2) * 0.7;
//Calculate impact parameter and choose the atom to scatter from.
//Do this for ion pairs 0,1 and 2,3.
if (ionCounter == 0)
{
delX1 = ions[0] - DiPrev;
delX2 = ions[1] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[0];
ions[0] = ions[1];
ions[1] = temp;
//cout << “Vertical Ions swapped” << endl;
}
}
if (ionCounter == 2)
{
delX1 = ions[2] - DiPrev;
delX2 = ions[3] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[2];
ions[2] = ions[3];
ions[3] = temp;
//cout << “Horizontal Ions swapped” << endl;
}
}
//now calculate impact parameter
if(neighborFlag == 0)
{
delX = ions[ionCounter] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
else if(neighborFlag == 1)
{
double impact[13] = {0.0};
double radial[13] = {0.0};
double S[13] = {0.0};
double sumS = 0.0;
double Probability[13] = {0.0};
double rnd_candidate = 0.0;
int selected_candidate = -1;
for(int ncount = 0; ncount <= 13; ncount++)
{
delX = neighborIonsBCC[ncount] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
//scatterIonPos = neighborIonsBCC[ncount];
impact[ncount] = p;
radial[ncount] = delX.magnitude();
S[ncount] = 1 / ( pow(impact[ncount],2) * radial[ncount] );
sumS += S[ncount];
//general scheme of selecting the neighbor ion
// if(p < pmax[LL])
// {
// scatterIonPos = neighborIonsBCC[ncount];
// //cout << “Neighbor “ << ncount << “ is selected” << endl;
// break;
// }
}
for(int ncount = 0; ncount <= 13; ncount++)
{
Probability[ncount] = S[ncount] / sumS;
}
//print out the probability array
cout << endl;
for(int ncount = 0; ncount <= 13; ncount++)
{
//cout << Probability[ncount] << “ “;
infoStream << Probability[ncount] << “ “;
}
infoStream << endl;
//cout << endl;
//random number between 0 and 1
rnd_candidate = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) );
//cout << “rand_candidate: “ << rnd_candidate << endl;
//choose the candidate for scattering
selected_candidate = whichNonUniformBin(rnd_candidate, Probability, 13);
//cout << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate <<
endl;
infoStream << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate
<< endl;
//assign the scatterIonPos variable to the selected neighbor
scatterIonPos = neighborIonsBCC[selected_candidate];
//cout << “Scattering Ion Position: “; scatterIonPos.printVector();
//find the essential quantities for the selected neighbor
delX = neighborIonsBCC[selected_candidate] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
//find eps and b using fi[LL][nn], using nn that I was supposed to find from above
//here im deliberately using nn = 1
eps = fi[LL][1] * e;
b = p / ai[LL][1];
if (eps > 10) //rutherford scattering
{
s2 = 1.0 / (1.0 + (1.0 + b * (1.0 + b)) * pow((2.0 * eps * b), 2) );
c2 = 1.0 - s2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
else //magic formula
{
r = b;
rr = -2.7 * log(eps * b);
if (rr >= b)//note >= sign instead < in trim85
{
rr = -2.7 * log(eps * rr);
if (rr >= b)//note >= sign instead < in trim85
{
r = rr;
}
}
//do while loop that replaces line 330 loop
do
{
ex1 = 0.18175 * exp(-3.1998 * r);
ex2 = 0.50986 * exp(-0.94229 * r);
ex3 = 0.28022 * exp(-0.4029 * r);
ex4 = 0.028171 * exp(-0.20162 * r);
v = (ex1 + ex2 + ex3 + ex4) / r;
v1 = -(v + 3.1998 * ex1 + 0.94229 * ex2 + 0.4029 * ex3 + 0.20162 * ex4) / r;
fr = b * b / r + v * r / eps - r;
fr1 = -b * b / (r * r) + (v + v1 * r) / eps - 1.0;
q = fr / fr1;
r = r - q;
}
while( (Abs(q / r)) > 0.001 );
roc = -2.0 * (eps - v) / v1;
sqe = sqrt(eps);
//5 parameter magic scattering calculation
//below is for universal potential
cc = (0.011615 + sqe) / (0.0071222 + sqe);
aa = 2.0 * eps * (1.0 + (0.99229 / sqe) ) * ( pow(b, cc) );
ff = ( sqrt(aa * aa + 1.0) - aa) * ( (9.3066 + eps) / (14.813 + eps) );
delta = (r - b) * aa * ff / (ff + 1.0);
co = (b + delta + roc) / (r + roc);
c2 = co * co;
s2 = 1.0 - c2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
Theta = acos(ct);
//we are done finding theta (in CM system). So calculate all other quantities.
//find separation and the separation vector.
phi = (Pi - Theta) / 2;
sep = p / tan(phi);
sepVector = lambda * sep;
//find theta in laboratory frame - psi
psi = atan(st / (ct + my[LL][1] ) );
//note: change my[LL][1] to my[LL][nn] when the above section is fixed.
if (psi < 0 ) psi = psi + Pi; //should I do this for crystals?
//find Di, the scattering point vector
Di = DiPrev + delX + pVector - sepVector;
//find new direction of motion
lambdaPrime = lambda * cos(psi) + pUnitVector * sin(psi);
lambdaPrime.normalize();
//find length of step, ls = distance of Di from DiPrev
ls = Di.getDistance(DiPrev);
//find energy lost due to electronic stopping, dee
ie = (int)(e/e0kev+0.5); //should it be 0.5? or less so that ie <=1000?
see = se[LL][ie];
if (e < e0kev) see = se[LL][1] * sqrt(e/e0kev);
dee = ls * see;
// den = energy transferred to recoil
den = ec[LL][1] * s2 * e; //note: I am using ec[LL][1] here instead of [LL][nn].
//cout << “den = “ << den << “, dee = “ << dee << endl;
infoStream << “den = “ << den << “, dee = “ << dee << endl;
e = e - den - dee;
//cout << endl<< “current ion energy: “ << e << endl;
if (dee > maximum) maximum = dee;
pl = pl + ls - tau;
//write the ion position to output file
outStream << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
if((ic%30)==0)
{
//cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
}
//determine which scatter plot Di’s x value belongs to.
//output the y and z coordinates to scatter plot file accordingly.
for(int cc = 0; cc <= numScatterPlotBins; cc++)
{
if( Di.x >= (scatterPlot[cc]) )
{
crystalMuonY = Di.y - translationY;
crystalMuonZ = Di.z - translationZ;
//cout << “scatter plot “ << ct << “: “ << scatterPlot[ct] << endl;
scatterStream << scatterPlot[cc] << “\t” << crystalMuonY << “\t” <<
crystalMuonZ << endl;
//set scatterPlot[ss] to a big number
scatterPlot[cc] = 10000;
//break out of this for loop
break;
}
}
//determine if Di is in the channeling region.
//insideChannel = Di.isInsidePolygon(ionsOrdered, 4);
//break out of parent loop if not inside the channel
if(insideChannel == 0)
{
cout << “Ion “ << ih << “ is out of Channel” << endl;
cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
break;
}
//determine which layer the next collision will be in
if (Di.x < 0.0) //particle is backscattered
{
backscattered = 1; //cout << “ion number “ << ih << “ backscattered.” << endl;
infoStream << “ion number “ << ih << “ backscattered.” << endl;
ib = ib + 1;
eb = eb + e;
break; //break out of ‘mother do loop’ and continue with the next session of
for loop.
}
//here we set the current or next layer the particle will be in
for (w = 1; w <= Layer; w++)
{
if ( (Di.x <= xx[w]) && (w == 1) )
{
LL = 1;
//cout << endl<<”ion is in layer “ << LL << endl;
break;
//break out of this For loop and go check if the particle is transmitted.
}
else if ( (Di.x <= xx[w]) && (Di.x > xx[w-1]) )
{
LL = w;
//cout << “ion is in layer “ << LL <<endl;
break; //break out of this For loop and go check if the particle is
transmitted.
}
}
//now, check for particle transmission, i.e. whether the particle went out of the
last layer.
if(Di.x >= xx[Layer])
{
//particle is transmitted, take care of appropriate variables and break
transmitted = 1;//cout << “ion number “ << ih << “ transmitted.” << endl;
it = it + 1;
et = et + e;
ia = 57.295779 * acos(cosin) / da + 1.0;
ie = 100 * e / e0 + 1.0;
//m[ie][ia] = m[ie][ia] + 1;//note: how is this possible? ie and ia should be
integers in order to access the elements of the array m[][]. But we calculate them as
doubles here!
break; //break out of the ‘mother’ do loop
}
//now take care of ionCounter and other variables for the next scattering
if(neighborFlag == 0)
{
if(ionCounter == 3)
{
//ionCounter = 0;
neighborFlag = 1;
scatterIonPos = ions[3];
//cout << endl << “got out of first two layers” << endl;
}
else
{
ionCounter++;
}
}
if(neighborFlag == 1)
{
//cout << “Updating Neighbor Ions” << endl;
neighborIonsBCC[0] = scatterIonPos + lx - ly + lz;
neighborIonsBCC[1] = scatterIonPos + lx + ly + lz;
neighborIonsBCC[2] = scatterIonPos + lx + ly - lz;
neighborIonsBCC[3] = scatterIonPos + lx - ly - lz;
neighborIonsBCC[4] = scatterIonPos + lx * 2;
neighborIonsBCC[5] = scatterIonPos - lx - ly - lz;
neighborIonsBCC[6] = scatterIonPos - lx + ly - lz;
neighborIonsBCC[7] = scatterIonPos - lx + ly + lz;
neighborIonsBCC[8] = scatterIonPos - lx - ly + lz;
neighborIonsBCC[9] = scatterIonPos + lz * 2;
neighborIonsBCC[10] = scatterIonPos - lz * 2;
neighborIonsBCC[11] = scatterIonPos + ly * 2;
neighborIonsBCC[12] = scatterIonPos - ly * 2;
neighborIonsBCC[13] = scatterIonPos - lx * 2;
}
//set DiPrev to Di
DiPrev = Di;
//update current lambda to lambdaPrime
lambda = lambdaPrime;
//now the while condition of the mother do loop checks if the particle has lesser
energy than our lowest energy limit, ef.
}
while(e > ef);
//since we are out of the mother do loop now, the particle must have come to a
stop. So, increase the final particle distributions if the particle has not been
transmitted or backscattered.
if( ((transmitted == 0)) && ((backscattered == 0)) && ((insideChannel == 1)) )
{
ip = (int)(pl/cw + 1.0);
if(ip > 100) ip = 100;
//ipl[ip] = ipl[ip] + 1;
xsum = xsum + Di.x;
//my own bin function
selectedXBin = whichBin(Di.x, xx[Layer], numXBin);
//write the selected bin to the output file
//outStream << selectedXBin << endl;
//cout << x << endl << xx[Layer] << endl << numXBin << endl << selectedXBin;
xBin[selectedXBin] = xBin[selectedXBin] + 1;
//print final x value for plotting histogram
//cout << “ion “ << ih << “ final x: “ << Di.x << endl;
infoStream << “ion “ << ih << “ final x: “ << Di.x << endl;
//cout << Di.x << “,”;
rangeStream << Di.x << endl;
plsum = plsum + pl;
icsum = icsum + ic;
//ipl is the ion path length - the total avg. distance the ion travels
regardless of direction before it comes to stop
}
//that brings us to the end of one ion’s journey, now go to next ion by going back
to the for loop’s beginning..
}
//and this ends the monte carlo loop function. Take care of necessary structures and
variables that need to be cleared/deleted
outStream.close();
scatterStream.close();
infoStream << “Number of Backscattered Ions: “ << ib << endl;
infoStream.close();
rangeStream.close();
}
int whichNonUniformBin(double e, double arr[], int numBins)
{
double low = 0, high = arr[0];
if((e>=low) && (e<high))
return 0;
else
{
for(int i = 0; i < numBins; i++)
{
low += arr[i];
high += arr[i+1];
//cout << “\tlow: “ << low << “, high:” << high << endl;
if((e>=low) && (e<high))
return i;
}
}
}
133
//============================================================================
// Name : monte.cpp
// Author : Nazmus Saquib
// Version :
// Copyright :
// Description : BCA code in C++
//============================================================================
#include “Globals.h”
#include “scoef.h”
#include “rstop.h”
#include “muscle_bca.h”
#include “vectorGeometry.h”
const int numXBin = 100;
const int numIons = 1;
int xBin[numXBin+1] = {0};
int selectedXBin = 0;
double rho[4]={0.0};
int n[]={0,0,0,0};
double e0kev, m1, cw, ed, latticeConst;
int z1, hn, iy, nowout;
double dx[3] = {0.0};
int zt[3][7] = {0};
double mt[3][7] = {0.};
double t[3][7] = {0.};
int Layer; //use this for number of layers rather than the L in the program;
//remember this cannot be set to 0. Other loops/arrays may start from
//0, but keep this >= 1;
//the arrays..
double my[3][7]= {0},
ai[3][7]= {0},
fi[3][7]= {0},
ec[3][7]= {0},
io[3][7]= {0},
k[3]= {0},
kl[3][7]= {0};
double vf[3][7]= {0},
mu[3]= {0},
ioniz[3]= {0},
h[3]= {0},
xx[3]= {0},
m2[3]= {0.0},
z2[3]= {0},
c[3]= {0},
epsbk[3]= {0},
arho[3]= {0};
double a[3]= {0},
f[3]= {0},
lm[3]= {0},
pmax[3]= {0},
fd[3]= {0},
kd[3]= {0},
sbk[3]= {0},
lf[3]= {0},
yy[8]= {0};
double se[3][1000]= {0.0},
seo[1000]= {0.0},
epsdg[3]= {0.0};
double ls = 0., lo = 0., maximum = 0.;
double xsum = 0, x2sum = 0, x3sum = 0, x4sum = 0, plsum = 0, pl2sum = 0;
double avex = 0, vari = 0, sigma = 0, v = 0, v2 = 0, Gamma = 0, beta = 0, y = 0, avepl
= 0, sigpl = 0, avecol = 0;
int i = 0, j = 0;
int ib = 0, it = 0;
double eb = 0.0, et = 0.0;
int icsum = 0;
double y2sum = 0, xy2sum = 0, x2y2su = 0, y4sum = 0;
double tau = 0;
int iii = -1;
//my dummy vars
int w; double q;
//my customized data structures or vars
scoefData scoefz1;
rstopData rstp;
//these vars (continuing from this line) are added later as needed, vars that were not
declared in the initialization of trim85 but showed up in the middle.
double e0, ef;
int iz;
double alfa, alpha;
double tmin, da;
double L0;
int iz1;
double ee;
int izt;
double nh;
double epso;
int ih;
double e;
//boolean for keeping track of a particle being transmitted or backscattered
int transmitted = 0;
int backscattered = 0;
//boolean for keeping track of channeling
int insideChannel = 1;
//boolean for determining whether to scatter from neighbor atoms
int neighborFlag = 0;
//main function
int main()
{
cout << “Initializing” << endl;
Initialize(“IronInput.dat”);
calculateAvgMassOfLayer();
getStoppingForTarget();
setInitialConditions();
MonteCarlo();
/* *********************** Testing Ground for arrays and variables
******************** */
for (w = 1; w <= 8; w++) cout << “\t “ << yy[w];
for (w = 1; w <= 3; w++) cout << “\n\t “ << xx[w];
cout << “CW or L0: “ << L0;
//(trouble! The values of n[] elements are changing like crazy)
cout << endl << n[0] << “\t” << n[1] << “\t” << n[2] << “\t” << n[3] << endl;
cout << endl << rho[0] << “\t” << rho[1] << “\t” << rho[2] << “\t” << rho[3] <<
“\t” << rho[4] << endl;
//test z2[], m2[] arrays
for (w = 1; w <= Layer; w++) cout << “\t “ << z2[w];
for (w = 1; w <= Layer; w++) cout << “\n\t “ << m2[w];
//test the se values
cout << endl << se[1][1000] << “ “ << se[2][1000] << “ “ << se[3][1000] << endl;
//test the se[] values by printing 10th element from the array (to be implemented)
//for (w = 1; w <= 100; w++)
//{
//for (int sss = 1; sss <= 50; sss++)
//{
//cout << “\t” << mpart[w][sss];
//}
//}
/* *********************** End of Testing Ground ************************** */
cout << endl;
//Now print values of each bin in xBin
//for (w = 1; w <= numXBin; w++) cout << xBin[w] << “,”;
//print final x values
cout << endl;
cout << “Number of Backscattered Ions: “ << ib << endl;
cout << “Number of Transmitted Ions: “ << it << endl;
return 0;
}
//end of main
//Helper functions follow from here
//initialize variables and setup each layer over here
void Initialize(char* filename)
{
//Read command file
ifstream instream;
instream.open(filename,ios::in);
cout << filename;
if (!instream)
{
exitOnError(filename);
}
instream >> e0kev >> z1 >> m1 >> latticeConst >> hn >> cw >> ed >> iy >> nowout;
instream >> dx[1] >> rho[1];
instream >> zt[1][1] >> mt[1][1] >> t[1][1];
instream >> n[1];
instream >> dx[2] >> rho[2];
instream >> zt[2][1] >> mt[2][1] >> t[2][1];
instream >> n[2];
instream >> dx[3] >> rho[3];
instream >> zt[3][1] >> mt[3][1] >> t[3][1];
instream >> n[3];
for (w = 0; w <= 3; w++)
{ if (n[w] != 1) n[w] = 1; }
instream.close();
Layer = 3;
//done with primary (crude) setup, off to reading scoef.dat file
iz = z1;
getstructScoef(iz, scoefz1, “scoef1.dat”); //used to get pcoef data yy in trim85
//so we put the values in yy here immediately
for (w = 1; w <= 8; w++)
{ yy[w] = scoefz1.pcoef[w]; }
//note: although yy turns out to be just a dummy array
e0 = e0kev*1000; //convert to ev.
if (ed == 0.) ed = 25.0;
ef = Max(5.0, e0kev*0.1);
//alfa = angle of incidence, alpha = radian of alfa
alfa = 0.;
alpha = alfa*Pi/180;
tmin = 5.0;
tau = 0.0;
da = 3.0;
if (iy == 0) iy = 16381;
//now calculate the total depth of each layer = xx(l), and grid spacing cw
xx[1] = dx[1];
for (w = 2; w <= 3; w++) { xx[w] = dx[w] + xx[w-1]; }
if (cw == 0) cw = 0.01*xx[3];
L0 = cw;
//take care of any custom variable or struct I made
rstp.vfermi = 0.0; //set this to 0. for the time being (see log for explanation)
//now, off to avg mass of layer in the next void function
}
//avg mass and atomic number of each layer
void calculateAvgMassOfLayer()
{
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
h[LL] = h[LL] + t[LL][w];
//cout << “testing here..” << rstp.vfermi << endl;
}
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
t[LL][w] = t[LL][w]/h[LL];
m2[LL] = m2[LL] + t[LL][w] * mt[LL][w];
z2[LL] = z2[LL] + t[LL][w] * zt[LL][w];
//note: z2 wont be an integer once t has a value other than 1.0??
//so are we calculating average atomic number here? why?
}
}
//done with this, off to finding electronic stopping powers in the next function
}
void getStoppingForTarget()
{
iz1 = z1; ee = 0;
for (int LL = 1; LL <= Layer; LL++)
{
arho[LL] = rho[LL] * 0.6022/(m2[LL]);
mu[LL] = m1/(m2[LL]);
int ii = n[LL];
for (int nn = 1; nn <= ii; nn++)
{
//set rstp.se[1..1000] = 0. Clear it for the next loop
for (w = 1; w <= 1000; w++)
{ rstp.se[w] = 0.; }
izt = zt[LL][nn];
//calling getrstop now. units, lfctr, vfermi = 1 (doesnt matter)
getrStop(iz1, izt, e0kev, 1, 1., 1., rstp); //rstp defined in header
//set this anyway, though I dont calculate this in RSTOP
vf[LL][nn] = rstp.vfermi; //which is just set 0 in the struct def.
for (w = 1; w <= 1000; w++)
{
se[LL][w] = se[LL][w] + rstp.se[w] * t[LL][nn] * arho[LL];
}
}
}
//now, off to setting up initial conditions next function
}
void setInitialConditions()
{
nh = hn; //number of histories
for (int LL = 1; LL <= Layer; LL++)
{
a[LL] = 0.5292 * 0.8853 / ( pow(z1, 0.23) + pow(z2[LL], 0.23) );
//now calculate the mean flight path with the conditions given in trim85
f[LL] = a[LL] * m2[LL] / ( z1 * z2[LL] * 14.4 * (m1 + m2[LL] ) );
epso = e0 * f[LL];
epsdg[LL] = tmin * f[LL] * pow( (1.0 + mu[LL]) , 2) / (4.0 * mu[LL]);
fd[LL] = 0.01 * pow( z2[LL], (-7.0/3.0) );
kd[LL] = 0.1334 * pow ( z2[LL], (2.0/3.0) ) / sqrt( m2[LL] );
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
my[LL][w] = m1/mt[LL][w];
ec[LL][w] = 4.0 * my[LL][w] / pow( ( 1.0 + my[LL][w] ), 2);
ai[LL][w] = 0.5292 * 0.8853 / ( pow(z1,0.23) + pow(zt[LL][w],0.23) );
fi[LL][w] = ai[LL][w] * mt[LL][w] / ( z1 * zt[LL][w] * 14.4 * ( m1 + mt[LL][w] ) );
}
}
cout << “Setup finished. Starting Monte Carlo Loops..”;
//off to monte carlo loop in next routine
}
void MonteCarlo()
{
//custom variables and arrays for this section
double e;
double cosin = 0.0, siny = 0.0, sine = 0.0, cosy = 0.0;
double pl = 0.0;
int ic;
int LL = 1;
double eps;
double eeg;
double p;
double b;
int ie, ia; //not sure if ie or ia should be double. They are used to access elements
of the m[][] array at some point
double see;
double dee;
double s2, c2, ct, st;
double r, rr;
double ex1, ex2, ex3, ex4;
double v, v1;
double fr, fr1;
double q;
double roc, sqe;
double cc, aa, ff;
double delta, co;
double den;
double phi, psi;
double x1;
int ip;
//variables for crystal calculations
double sep = 0.0;
int ionCounter = 0;
double p1, p2;
double Theta = 0.0;
double rTheta = 0.0, rPhi = 0.0;
double thetaThreshold = 0.5;
double crystalMuonY = 0.0, crystalMuonZ = 0.0;
//amount of translations in y and z axes
double translationY = 0.0, translationZ = 0.0;
//Scatter Plot variables
const int numScatterPlotBins = 5;
double scatterPlot[numScatterPlotBins + 1] = {0.0};
//Vector declarations
//lattice constant of Target (input from file)
double latticeConstant = latticeConst;
Vector3 ions[4];
Vector3 ionsOrdered[4];
Vector3 neighborIonsBCC[14];
Vector3 neighborIonsFCC[14];
Vector3 ionTranslationY(0,translationY,0);
Vector3 ionTranslationZ(0,0,translationZ);
Vector3 unitzplus, unitzminus, unityplus, unityminus, unitxplus, unitxminus;
unitzplus.z = 1;
unitzminus.z = -1;
unityplus.y = 1;
unityminus.y = -1;
unitxplus.x = 1;
unitxminus.x = -1;
Vector3 initialDirection(1,0,0);
Vector3 d;
d.x = 1;
d *= latticeConstant/2;
Vector3 lx(latticeConstant/2, 0, 0);
Vector3 ly(0, latticeConstant/2, 0);
Vector3 lz(0, 0, latticeConstant/2);
Vector3 lambda;
Vector3 lambdaPrime;
Vector3 pVector;
Vector3 pUnitVector;
Vector3 sepVector;
Vector3 Di;
Vector3 DiPrev;
//Vector3 DiPrevToDi;
Vector3 delX;
Vector3 delX1, delX2;
Vector3 dummy1, dummy2, temp;
Vector3 scatterIonPos;
//initialize the random number generator
srand(time(NULL));
//open file to write output
ofstream outStream;
outStream.open(“coords0.txt”);
if(outStream.fail())
{
exitOnError(“Could not open Output file”);
}
//write basic information in the output file
//number of ions, ion energy, total depth, depth of each layer
outStream << nh << “\t” << e0kev << “\t” << xx[Layer] << “\t” << dx[1] << “\t”
<< dx[2] << “\t” << dx[3] << endl;
//open scatter plot file to write current Y and Z coordinates of muons at designated
intervals
ofstream scatterStream;
scatterStream.open(“scatterOut1.txt”);
if(scatterStream.fail())
{
exitOnError(“Could not open Scatter Plot Output file”);
}
//open range distribution file to write final X coordinates of muons
ofstream rangeStream;
rangeStream.open(“rangeOut1.txt”);
if(rangeStream.fail())
{
exitOnError(“Could not open Range Distribution Output file”);
}
//Open general information dump file
ofstream infoStream;
infoStream.open(“info1.txt”);
if(infoStream.fail())
{
exitOnError(“Could not open general information Output file”);
}
//Entering the target
//First set up for the top layer
for (ih = 1; ih <= nh; ih++)
{
avex = xsum / Max(1.0, (float)(ih - ib - it - 1));
if (talk == 2) cout << “Average ion range so far: “ << avex << “ angstroms.”
<<endl;
if (talk > 2) cout << “Now starting ion number “ << ih << endl;
e = e0;
//set scatterPlot array (the intervals)
scatterPlot[0] = 10;
scatterPlot[1] = 30;
scatterPlot[2] = 50;
scatterPlot[3] = 100;
scatterPlot[4] = 150;
scatterPlot[5] = 200;
/*
for(int ccc = 0; ccc <= numScatterPlotBins; ccc++)
{
cout << “scatter plot “ << ccc << “: “ << scatterPlot[ccc] << endl;
}
*/
//Initial Ion Positions
ions[0] = d + ionTranslationZ + unitzminus * (latticeConstant/2);
ions[1] = d + ionTranslationZ + unitzplus * (latticeConstant/2);
ions[2] = d * 2 + ionTranslationY + unityminus * (latticeConstant/2);
ions[3] = d * 2 + ionTranslationY + unityplus * (latticeConstant/2);
//Create a polygon that resides on the lateral axes.
//The points are put on anticlockwise order, which is important for
//testing whether the test point lies on this polygon
ionsOrdered[0] = ions[0];
ionsOrdered[1] = ions[2];
ionsOrdered[2] = ions[1];
ionsOrdered[3] = ions[3];
//generate random theta and phi angles.
rTheta = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * thetaThreshold;
rPhi = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * 2 * Pi;
//find corresponding x, y and z components of the direction vector.
//radius of the direction vector is 1
initialDirection.x = cos(rTheta);
initialDirection.z = sin(rTheta) * cos(rPhi);
initialDirection.y = sin(rTheta) * sin(rPhi);
//set the counter to 0 for a new ion
ionCounter = 0;
pl = 0.0;
ic = 0;
//set initial DiPrev - the origin
DiPrev.x = 0.0; DiPrev.y = 0.0; DiPrev.z = 0.0;
//set initial lambda, the direction of motion. Normalize it.
lambda.clear();
lambda = initialDirection;
lambda.normalize();
//set initial delX to origin
delX.clear();
//clear the dummy delX vectors, set them to origin
delX1.clear();
delX2.clear();
dummy1.clear();
dummy2.clear();
temp.clear();
LL = 1;
//set transmitted and backscattered to false
transmitted = 0;
backscattered = 0;
//set channeling to true
insideChannel = 1;
neighborFlag = 0;
//write the initial coordinates to the output file
outStream << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << endl << “Initial: “;
//cout << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << “r1 = “ << r1 << endl;
//cycle for each collision until the energy of the particle becomes too low, or
the particle backscatters, or it goes out of the last layer (transmission)
//needs a do while loop here,
//which I will mention as the ‘mother loop’ from now.
do
{
ic = ic + 1;
eps = e * f[LL];
eeg = sqrt(eps*epsdg[LL]);
//pmax[LL] = a[LL] / (eeg + sqrt(eeg) + 0.125 * pow( eeg, 0.1) );
pmax[LL] = sqrt(3) * (latticeConstant / 2) * 0.7;
//Calculate impact parameter and choose the atom to scatter from.
//Do this for ion pairs 0,1 and 2,3.
if (ionCounter == 0)
{
delX1 = ions[0] - DiPrev;
delX2 = ions[1] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[0];
ions[0] = ions[1];
ions[1] = temp;
//cout << “Vertical Ions swapped” << endl;
}
}
if (ionCounter == 2)
{
delX1 = ions[2] - DiPrev;
delX2 = ions[3] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[2];
ions[2] = ions[3];
ions[3] = temp;
//cout << “Horizontal Ions swapped” << endl;
}
}
//now calculate impact parameter
if(neighborFlag == 0)
{
delX = ions[ionCounter] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
else if(neighborFlag == 1)
{
double impact[13] = {0.0};
double radial[13] = {0.0};
double S[13] = {0.0};
double sumS = 0.0;
double Probability[13] = {0.0};
double rnd_candidate = 0.0;
int selected_candidate = -1;
for(int ncount = 0; ncount <= 13; ncount++)
{
delX = neighborIonsBCC[ncount] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
//scatterIonPos = neighborIonsBCC[ncount];
impact[ncount] = p;
radial[ncount] = delX.magnitude();
S[ncount] = 1 / ( pow(impact[ncount],2) * radial[ncount] );
sumS += S[ncount];
//general scheme of selecting the neighbor ion
// if(p < pmax[LL])
// {
// scatterIonPos = neighborIonsBCC[ncount];
// //cout << “Neighbor “ << ncount << “ is selected” << endl;
// break;
// }
}
for(int ncount = 0; ncount <= 13; ncount++)
{
Probability[ncount] = S[ncount] / sumS;
}
//print out the probability array
cout << endl;
for(int ncount = 0; ncount <= 13; ncount++)
{
//cout << Probability[ncount] << “ “;
infoStream << Probability[ncount] << “ “;
}
infoStream << endl;
//cout << endl;
//random number between 0 and 1
rnd_candidate = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) );
//cout << “rand_candidate: “ << rnd_candidate << endl;
//choose the candidate for scattering
selected_candidate = whichNonUniformBin(rnd_candidate, Probability, 13);
//cout << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate <<
endl;
infoStream << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate
<< endl;
//assign the scatterIonPos variable to the selected neighbor
scatterIonPos = neighborIonsBCC[selected_candidate];
//cout << “Scattering Ion Position: “; scatterIonPos.printVector();
//find the essential quantities for the selected neighbor
delX = neighborIonsBCC[selected_candidate] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
//find eps and b using fi[LL][nn], using nn that I was supposed to find from above
//here im deliberately using nn = 1
eps = fi[LL][1] * e;
b = p / ai[LL][1];
if (eps > 10) //rutherford scattering
{
s2 = 1.0 / (1.0 + (1.0 + b * (1.0 + b)) * pow((2.0 * eps * b), 2) );
c2 = 1.0 - s2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
else //magic formula
{
r = b;
rr = -2.7 * log(eps * b);
if (rr >= b)//note >= sign instead < in trim85
{
rr = -2.7 * log(eps * rr);
if (rr >= b)//note >= sign instead < in trim85
{
r = rr;
}
}
//do while loop that replaces line 330 loop
do
{
ex1 = 0.18175 * exp(-3.1998 * r);
ex2 = 0.50986 * exp(-0.94229 * r);
ex3 = 0.28022 * exp(-0.4029 * r);
ex4 = 0.028171 * exp(-0.20162 * r);
v = (ex1 + ex2 + ex3 + ex4) / r;
v1 = -(v + 3.1998 * ex1 + 0.94229 * ex2 + 0.4029 * ex3 + 0.20162 * ex4) / r;
fr = b * b / r + v * r / eps - r;
fr1 = -b * b / (r * r) + (v + v1 * r) / eps - 1.0;
q = fr / fr1;
r = r - q;
}
while( (Abs(q / r)) > 0.001 );
roc = -2.0 * (eps - v) / v1;
sqe = sqrt(eps);
//5 parameter magic scattering calculation
//below is for universal potential
cc = (0.011615 + sqe) / (0.0071222 + sqe);
aa = 2.0 * eps * (1.0 + (0.99229 / sqe) ) * ( pow(b, cc) );
ff = ( sqrt(aa * aa + 1.0) - aa) * ( (9.3066 + eps) / (14.813 + eps) );
delta = (r - b) * aa * ff / (ff + 1.0);
co = (b + delta + roc) / (r + roc);
c2 = co * co;
s2 = 1.0 - c2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
Theta = acos(ct);
//we are done finding theta (in CM system). So calculate all other quantities.
//find separation and the separation vector.
phi = (Pi - Theta) / 2;
sep = p / tan(phi);
sepVector = lambda * sep;
//find theta in laboratory frame - psi
psi = atan(st / (ct + my[LL][1] ) );
//note: change my[LL][1] to my[LL][nn] when the above section is fixed.
if (psi < 0 ) psi = psi + Pi; //should I do this for crystals?
//find Di, the scattering point vector
Di = DiPrev + delX + pVector - sepVector;
//find new direction of motion
lambdaPrime = lambda * cos(psi) + pUnitVector * sin(psi);
lambdaPrime.normalize();
//find length of step, ls = distance of Di from DiPrev
ls = Di.getDistance(DiPrev);
//find energy lost due to electronic stopping, dee
ie = (int)(e/e0kev+0.5); //should it be 0.5? or less so that ie <=1000?
see = se[LL][ie];
if (e < e0kev) see = se[LL][1] * sqrt(e/e0kev);
dee = ls * see;
// den = energy transferred to recoil
den = ec[LL][1] * s2 * e; //note: I am using ec[LL][1] here instead of [LL][nn].
//cout << “den = “ << den << “, dee = “ << dee << endl;
infoStream << “den = “ << den << “, dee = “ << dee << endl;
e = e - den - dee;
//cout << endl<< “current ion energy: “ << e << endl;
if (dee > maximum) maximum = dee;
pl = pl + ls - tau;
//write the ion position to output file
outStream << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
if((ic%30)==0)
{
//cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
}
//determine which scatter plot Di’s x value belongs to.
//output the y and z coordinates to scatter plot file accordingly.
for(int cc = 0; cc <= numScatterPlotBins; cc++)
{
if( Di.x >= (scatterPlot[cc]) )
{
crystalMuonY = Di.y - translationY;
crystalMuonZ = Di.z - translationZ;
//cout << “scatter plot “ << ct << “: “ << scatterPlot[ct] << endl;
scatterStream << scatterPlot[cc] << “\t” << crystalMuonY << “\t” <<
crystalMuonZ << endl;
//set scatterPlot[ss] to a big number
scatterPlot[cc] = 10000;
//break out of this for loop
break;
}
}
//determine if Di is in the channeling region.
//insideChannel = Di.isInsidePolygon(ionsOrdered, 4);
//break out of parent loop if not inside the channel
if(insideChannel == 0)
{
cout << “Ion “ << ih << “ is out of Channel” << endl;
cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
break;
}
//determine which layer the next collision will be in
if (Di.x < 0.0) //particle is backscattered
{
backscattered = 1; //cout << “ion number “ << ih << “ backscattered.” << endl;
infoStream << “ion number “ << ih << “ backscattered.” << endl;
ib = ib + 1;
eb = eb + e;
break; //break out of ‘mother do loop’ and continue with the next session of
for loop.
}
//here we set the current or next layer the particle will be in
for (w = 1; w <= Layer; w++)
{
if ( (Di.x <= xx[w]) && (w == 1) )
{
LL = 1;
//cout << endl<<”ion is in layer “ << LL << endl;
break;
//break out of this For loop and go check if the particle is transmitted.
}
else if ( (Di.x <= xx[w]) && (Di.x > xx[w-1]) )
{
LL = w;
//cout << “ion is in layer “ << LL <<endl;
break; //break out of this For loop and go check if the particle is
transmitted.
}
}
//now, check for particle transmission, i.e. whether the particle went out of the
last layer.
if(Di.x >= xx[Layer])
{
//particle is transmitted, take care of appropriate variables and break
transmitted = 1;//cout << “ion number “ << ih << “ transmitted.” << endl;
it = it + 1;
et = et + e;
ia = 57.295779 * acos(cosin) / da + 1.0;
ie = 100 * e / e0 + 1.0;
//m[ie][ia] = m[ie][ia] + 1;//note: how is this possible? ie and ia should be
integers in order to access the elements of the array m[][]. But we calculate them as
doubles here!
break; //break out of the ‘mother’ do loop
}
//now take care of ionCounter and other variables for the next scattering
if(neighborFlag == 0)
{
if(ionCounter == 3)
{
//ionCounter = 0;
neighborFlag = 1;
scatterIonPos = ions[3];
//cout << endl << “got out of first two layers” << endl;
}
else
{
ionCounter++;
}
}
if(neighborFlag == 1)
{
//cout << “Updating Neighbor Ions” << endl;
neighborIonsBCC[0] = scatterIonPos + lx - ly + lz;
neighborIonsBCC[1] = scatterIonPos + lx + ly + lz;
neighborIonsBCC[2] = scatterIonPos + lx + ly - lz;
neighborIonsBCC[3] = scatterIonPos + lx - ly - lz;
neighborIonsBCC[4] = scatterIonPos + lx * 2;
neighborIonsBCC[5] = scatterIonPos - lx - ly - lz;
neighborIonsBCC[6] = scatterIonPos - lx + ly - lz;
neighborIonsBCC[7] = scatterIonPos - lx + ly + lz;
neighborIonsBCC[8] = scatterIonPos - lx - ly + lz;
neighborIonsBCC[9] = scatterIonPos + lz * 2;
neighborIonsBCC[10] = scatterIonPos - lz * 2;
neighborIonsBCC[11] = scatterIonPos + ly * 2;
neighborIonsBCC[12] = scatterIonPos - ly * 2;
neighborIonsBCC[13] = scatterIonPos - lx * 2;
}
//set DiPrev to Di
DiPrev = Di;
//update current lambda to lambdaPrime
lambda = lambdaPrime;
//now the while condition of the mother do loop checks if the particle has lesser
energy than our lowest energy limit, ef.
}
while(e > ef);
//since we are out of the mother do loop now, the particle must have come to a
stop. So, increase the final particle distributions if the particle has not been
transmitted or backscattered.
if( ((transmitted == 0)) && ((backscattered == 0)) && ((insideChannel == 1)) )
{
ip = (int)(pl/cw + 1.0);
if(ip > 100) ip = 100;
//ipl[ip] = ipl[ip] + 1;
xsum = xsum + Di.x;
//my own bin function
selectedXBin = whichBin(Di.x, xx[Layer], numXBin);
//write the selected bin to the output file
//outStream << selectedXBin << endl;
//cout << x << endl << xx[Layer] << endl << numXBin << endl << selectedXBin;
xBin[selectedXBin] = xBin[selectedXBin] + 1;
//print final x value for plotting histogram
//cout << “ion “ << ih << “ final x: “ << Di.x << endl;
infoStream << “ion “ << ih << “ final x: “ << Di.x << endl;
//cout << Di.x << “,”;
rangeStream << Di.x << endl;
plsum = plsum + pl;
icsum = icsum + ic;
//ipl is the ion path length - the total avg. distance the ion travels
regardless of direction before it comes to stop
}
//that brings us to the end of one ion’s journey, now go to next ion by going back
to the for loop’s beginning..
}
//and this ends the monte carlo loop function. Take care of necessary structures and
variables that need to be cleared/deleted
outStream.close();
scatterStream.close();
infoStream << “Number of Backscattered Ions: “ << ib << endl;
infoStream.close();
rangeStream.close();
}
int whichNonUniformBin(double e, double arr[], int numBins)
{
double low = 0, high = arr[0];
if((e>=low) && (e<high))
return 0;
else
{
for(int i = 0; i < numBins; i++)
{
low += arr[i];
high += arr[i+1];
//cout << “\tlow: “ << low << “, high:” << high << endl;
if((e>=low) && (e<high))
return i;
}
}
}
134
//============================================================================
// Name : monte.cpp
// Author : Nazmus Saquib
// Version :
// Copyright :
// Description : BCA code in C++
//============================================================================
#include “Globals.h”
#include “scoef.h”
#include “rstop.h”
#include “muscle_bca.h”
#include “vectorGeometry.h”
const int numXBin = 100;
const int numIons = 1;
int xBin[numXBin+1] = {0};
int selectedXBin = 0;
double rho[4]={0.0};
int n[]={0,0,0,0};
double e0kev, m1, cw, ed, latticeConst;
int z1, hn, iy, nowout;
double dx[3] = {0.0};
int zt[3][7] = {0};
double mt[3][7] = {0.};
double t[3][7] = {0.};
int Layer; //use this for number of layers rather than the L in the program;
//remember this cannot be set to 0. Other loops/arrays may start from
//0, but keep this >= 1;
//the arrays..
double my[3][7]= {0},
ai[3][7]= {0},
fi[3][7]= {0},
ec[3][7]= {0},
io[3][7]= {0},
k[3]= {0},
kl[3][7]= {0};
double vf[3][7]= {0},
mu[3]= {0},
ioniz[3]= {0},
h[3]= {0},
xx[3]= {0},
m2[3]= {0.0},
z2[3]= {0},
c[3]= {0},
epsbk[3]= {0},
arho[3]= {0};
double a[3]= {0},
f[3]= {0},
lm[3]= {0},
pmax[3]= {0},
fd[3]= {0},
kd[3]= {0},
sbk[3]= {0},
lf[3]= {0},
yy[8]= {0};
double se[3][1000]= {0.0},
seo[1000]= {0.0},
epsdg[3]= {0.0};
double ls = 0., lo = 0., maximum = 0.;
double xsum = 0, x2sum = 0, x3sum = 0, x4sum = 0, plsum = 0, pl2sum = 0;
double avex = 0, vari = 0, sigma = 0, v = 0, v2 = 0, Gamma = 0, beta = 0, y = 0, avepl
= 0, sigpl = 0, avecol = 0;
int i = 0, j = 0;
int ib = 0, it = 0;
double eb = 0.0, et = 0.0;
int icsum = 0;
double y2sum = 0, xy2sum = 0, x2y2su = 0, y4sum = 0;
double tau = 0;
int iii = -1;
//my dummy vars
int w; double q;
//my customized data structures or vars
scoefData scoefz1;
rstopData rstp;
//these vars (continuing from this line) are added later as needed, vars that were not
declared in the initialization of trim85 but showed up in the middle.
double e0, ef;
int iz;
double alfa, alpha;
double tmin, da;
double L0;
int iz1;
double ee;
int izt;
double nh;
double epso;
int ih;
double e;
//boolean for keeping track of a particle being transmitted or backscattered
int transmitted = 0;
int backscattered = 0;
//boolean for keeping track of channeling
int insideChannel = 1;
//boolean for determining whether to scatter from neighbor atoms
int neighborFlag = 0;
//main function
int main()
{
cout << “Initializing” << endl;
Initialize(“IronInput.dat”);
calculateAvgMassOfLayer();
getStoppingForTarget();
setInitialConditions();
MonteCarlo();
/* *********************** Testing Ground for arrays and variables
******************** */
for (w = 1; w <= 8; w++) cout << “\t “ << yy[w];
for (w = 1; w <= 3; w++) cout << “\n\t “ << xx[w];
cout << “CW or L0: “ << L0;
//(trouble! The values of n[] elements are changing like crazy)
cout << endl << n[0] << “\t” << n[1] << “\t” << n[2] << “\t” << n[3] << endl;
cout << endl << rho[0] << “\t” << rho[1] << “\t” << rho[2] << “\t” << rho[3] <<
“\t” << rho[4] << endl;
//test z2[], m2[] arrays
for (w = 1; w <= Layer; w++) cout << “\t “ << z2[w];
for (w = 1; w <= Layer; w++) cout << “\n\t “ << m2[w];
//test the se values
cout << endl << se[1][1000] << “ “ << se[2][1000] << “ “ << se[3][1000] << endl;
//test the se[] values by printing 10th element from the array (to be implemented)
//for (w = 1; w <= 100; w++)
//{
//for (int sss = 1; sss <= 50; sss++)
//{
//cout << “\t” << mpart[w][sss];
//}
//}
/* *********************** End of Testing Ground ************************** */
cout << endl;
//Now print values of each bin in xBin
//for (w = 1; w <= numXBin; w++) cout << xBin[w] << “,”;
//print final x values
cout << endl;
cout << “Number of Backscattered Ions: “ << ib << endl;
cout << “Number of Transmitted Ions: “ << it << endl;
return 0;
}
//end of main
//Helper functions follow from here
//initialize variables and setup each layer over here
void Initialize(char* filename)
{
//Read command file
ifstream instream;
instream.open(filename,ios::in);
cout << filename;
if (!instream)
{
exitOnError(filename);
}
instream >> e0kev >> z1 >> m1 >> latticeConst >> hn >> cw >> ed >> iy >> nowout;
instream >> dx[1] >> rho[1];
instream >> zt[1][1] >> mt[1][1] >> t[1][1];
instream >> n[1];
instream >> dx[2] >> rho[2];
instream >> zt[2][1] >> mt[2][1] >> t[2][1];
instream >> n[2];
instream >> dx[3] >> rho[3];
instream >> zt[3][1] >> mt[3][1] >> t[3][1];
instream >> n[3];
for (w = 0; w <= 3; w++)
{ if (n[w] != 1) n[w] = 1; }
instream.close();
Layer = 3;
//done with primary (crude) setup, off to reading scoef.dat file
iz = z1;
getstructScoef(iz, scoefz1, “scoef1.dat”); //used to get pcoef data yy in trim85
//so we put the values in yy here immediately
for (w = 1; w <= 8; w++)
{ yy[w] = scoefz1.pcoef[w]; }
//note: although yy turns out to be just a dummy array
e0 = e0kev*1000; //convert to ev.
if (ed == 0.) ed = 25.0;
ef = Max(5.0, e0kev*0.1);
//alfa = angle of incidence, alpha = radian of alfa
alfa = 0.;
alpha = alfa*Pi/180;
tmin = 5.0;
tau = 0.0;
da = 3.0;
if (iy == 0) iy = 16381;
//now calculate the total depth of each layer = xx(l), and grid spacing cw
xx[1] = dx[1];
for (w = 2; w <= 3; w++) { xx[w] = dx[w] + xx[w-1]; }
if (cw == 0) cw = 0.01*xx[3];
L0 = cw;
//take care of any custom variable or struct I made
rstp.vfermi = 0.0; //set this to 0. for the time being (see log for explanation)
//now, off to avg mass of layer in the next void function
}
//avg mass and atomic number of each layer
void calculateAvgMassOfLayer()
{
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
h[LL] = h[LL] + t[LL][w];
//cout << “testing here..” << rstp.vfermi << endl;
}
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
t[LL][w] = t[LL][w]/h[LL];
m2[LL] = m2[LL] + t[LL][w] * mt[LL][w];
z2[LL] = z2[LL] + t[LL][w] * zt[LL][w];
//note: z2 wont be an integer once t has a value other than 1.0??
//so are we calculating average atomic number here? why?
}
}
//done with this, off to finding electronic stopping powers in the next function
}
void getStoppingForTarget()
{
iz1 = z1; ee = 0;
for (int LL = 1; LL <= Layer; LL++)
{
arho[LL] = rho[LL] * 0.6022/(m2[LL]);
mu[LL] = m1/(m2[LL]);
int ii = n[LL];
for (int nn = 1; nn <= ii; nn++)
{
//set rstp.se[1..1000] = 0. Clear it for the next loop
for (w = 1; w <= 1000; w++)
{ rstp.se[w] = 0.; }
izt = zt[LL][nn];
//calling getrstop now. units, lfctr, vfermi = 1 (doesnt matter)
getrStop(iz1, izt, e0kev, 1, 1., 1., rstp); //rstp defined in header
//set this anyway, though I dont calculate this in RSTOP
vf[LL][nn] = rstp.vfermi; //which is just set 0 in the struct def.
for (w = 1; w <= 1000; w++)
{
se[LL][w] = se[LL][w] + rstp.se[w] * t[LL][nn] * arho[LL];
}
}
}
//now, off to setting up initial conditions next function
}
void setInitialConditions()
{
nh = hn; //number of histories
for (int LL = 1; LL <= Layer; LL++)
{
a[LL] = 0.5292 * 0.8853 / ( pow(z1, 0.23) + pow(z2[LL], 0.23) );
//now calculate the mean flight path with the conditions given in trim85
f[LL] = a[LL] * m2[LL] / ( z1 * z2[LL] * 14.4 * (m1 + m2[LL] ) );
epso = e0 * f[LL];
epsdg[LL] = tmin * f[LL] * pow( (1.0 + mu[LL]) , 2) / (4.0 * mu[LL]);
fd[LL] = 0.01 * pow( z2[LL], (-7.0/3.0) );
kd[LL] = 0.1334 * pow ( z2[LL], (2.0/3.0) ) / sqrt( m2[LL] );
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
my[LL][w] = m1/mt[LL][w];
ec[LL][w] = 4.0 * my[LL][w] / pow( ( 1.0 + my[LL][w] ), 2);
ai[LL][w] = 0.5292 * 0.8853 / ( pow(z1,0.23) + pow(zt[LL][w],0.23) );
fi[LL][w] = ai[LL][w] * mt[LL][w] / ( z1 * zt[LL][w] * 14.4 * ( m1 + mt[LL][w] ) );
}
}
cout << “Setup finished. Starting Monte Carlo Loops..”;
//off to monte carlo loop in next routine
}
void MonteCarlo()
{
//custom variables and arrays for this section
double e;
double cosin = 0.0, siny = 0.0, sine = 0.0, cosy = 0.0;
double pl = 0.0;
int ic;
int LL = 1;
double eps;
double eeg;
double p;
double b;
int ie, ia; //not sure if ie or ia should be double. They are used to access elements
of the m[][] array at some point
double see;
double dee;
double s2, c2, ct, st;
double r, rr;
double ex1, ex2, ex3, ex4;
double v, v1;
double fr, fr1;
double q;
double roc, sqe;
double cc, aa, ff;
double delta, co;
double den;
double phi, psi;
double x1;
int ip;
//variables for crystal calculations
double sep = 0.0;
int ionCounter = 0;
double p1, p2;
double Theta = 0.0;
double rTheta = 0.0, rPhi = 0.0;
double thetaThreshold = 0.5;
double crystalMuonY = 0.0, crystalMuonZ = 0.0;
//amount of translations in y and z axes
double translationY = 0.0, translationZ = 0.0;
//Scatter Plot variables
const int numScatterPlotBins = 5;
double scatterPlot[numScatterPlotBins + 1] = {0.0};
//Vector declarations
//lattice constant of Target (input from file)
double latticeConstant = latticeConst;
Vector3 ions[4];
Vector3 ionsOrdered[4];
Vector3 neighborIonsBCC[14];
Vector3 neighborIonsFCC[14];
Vector3 ionTranslationY(0,translationY,0);
Vector3 ionTranslationZ(0,0,translationZ);
Vector3 unitzplus, unitzminus, unityplus, unityminus, unitxplus, unitxminus;
unitzplus.z = 1;
unitzminus.z = -1;
unityplus.y = 1;
unityminus.y = -1;
unitxplus.x = 1;
unitxminus.x = -1;
Vector3 initialDirection(1,0,0);
Vector3 d;
d.x = 1;
d *= latticeConstant/2;
Vector3 lx(latticeConstant/2, 0, 0);
Vector3 ly(0, latticeConstant/2, 0);
Vector3 lz(0, 0, latticeConstant/2);
Vector3 lambda;
Vector3 lambdaPrime;
Vector3 pVector;
Vector3 pUnitVector;
Vector3 sepVector;
Vector3 Di;
Vector3 DiPrev;
//Vector3 DiPrevToDi;
Vector3 delX;
Vector3 delX1, delX2;
Vector3 dummy1, dummy2, temp;
Vector3 scatterIonPos;
//initialize the random number generator
srand(time(NULL));
//open file to write output
ofstream outStream;
outStream.open(“coords0.txt”);
if(outStream.fail())
{
exitOnError(“Could not open Output file”);
}
//write basic information in the output file
//number of ions, ion energy, total depth, depth of each layer
outStream << nh << “\t” << e0kev << “\t” << xx[Layer] << “\t” << dx[1] << “\t”
<< dx[2] << “\t” << dx[3] << endl;
//open scatter plot file to write current Y and Z coordinates of muons at designated
intervals
ofstream scatterStream;
scatterStream.open(“scatterOut1.txt”);
if(scatterStream.fail())
{
exitOnError(“Could not open Scatter Plot Output file”);
}
//open range distribution file to write final X coordinates of muons
ofstream rangeStream;
rangeStream.open(“rangeOut1.txt”);
if(rangeStream.fail())
{
exitOnError(“Could not open Range Distribution Output file”);
}
//Open general information dump file
ofstream infoStream;
infoStream.open(“info1.txt”);
if(infoStream.fail())
{
exitOnError(“Could not open general information Output file”);
}
//Entering the target
//First set up for the top layer
for (ih = 1; ih <= nh; ih++)
{
avex = xsum / Max(1.0, (float)(ih - ib - it - 1));
if (talk == 2) cout << “Average ion range so far: “ << avex << “ angstroms.”
<<endl;
if (talk > 2) cout << “Now starting ion number “ << ih << endl;
e = e0;
//set scatterPlot array (the intervals)
scatterPlot[0] = 10;
scatterPlot[1] = 30;
scatterPlot[2] = 50;
scatterPlot[3] = 100;
scatterPlot[4] = 150;
scatterPlot[5] = 200;
/*
for(int ccc = 0; ccc <= numScatterPlotBins; ccc++)
{
cout << “scatter plot “ << ccc << “: “ << scatterPlot[ccc] << endl;
}
*/
//Initial Ion Positions
ions[0] = d + ionTranslationZ + unitzminus * (latticeConstant/2);
ions[1] = d + ionTranslationZ + unitzplus * (latticeConstant/2);
ions[2] = d * 2 + ionTranslationY + unityminus * (latticeConstant/2);
ions[3] = d * 2 + ionTranslationY + unityplus * (latticeConstant/2);
//Create a polygon that resides on the lateral axes.
//The points are put on anticlockwise order, which is important for
//testing whether the test point lies on this polygon
ionsOrdered[0] = ions[0];
ionsOrdered[1] = ions[2];
ionsOrdered[2] = ions[1];
ionsOrdered[3] = ions[3];
//generate random theta and phi angles.
rTheta = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * thetaThreshold;
rPhi = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * 2 * Pi;
//find corresponding x, y and z components of the direction vector.
//radius of the direction vector is 1
initialDirection.x = cos(rTheta);
initialDirection.z = sin(rTheta) * cos(rPhi);
initialDirection.y = sin(rTheta) * sin(rPhi);
//set the counter to 0 for a new ion
ionCounter = 0;
pl = 0.0;
ic = 0;
//set initial DiPrev - the origin
DiPrev.x = 0.0; DiPrev.y = 0.0; DiPrev.z = 0.0;
//set initial lambda, the direction of motion. Normalize it.
lambda.clear();
lambda = initialDirection;
lambda.normalize();
//set initial delX to origin
delX.clear();
//clear the dummy delX vectors, set them to origin
delX1.clear();
delX2.clear();
dummy1.clear();
dummy2.clear();
temp.clear();
LL = 1;
//set transmitted and backscattered to false
transmitted = 0;
backscattered = 0;
//set channeling to true
insideChannel = 1;
neighborFlag = 0;
//write the initial coordinates to the output file
outStream << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << endl << “Initial: “;
//cout << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << “r1 = “ << r1 << endl;
//cycle for each collision until the energy of the particle becomes too low, or
the particle backscatters, or it goes out of the last layer (transmission)
//needs a do while loop here,
//which I will mention as the ‘mother loop’ from now.
do
{
ic = ic + 1;
eps = e * f[LL];
eeg = sqrt(eps*epsdg[LL]);
//pmax[LL] = a[LL] / (eeg + sqrt(eeg) + 0.125 * pow( eeg, 0.1) );
pmax[LL] = sqrt(3) * (latticeConstant / 2) * 0.7;
//Calculate impact parameter and choose the atom to scatter from.
//Do this for ion pairs 0,1 and 2,3.
if (ionCounter == 0)
{
delX1 = ions[0] - DiPrev;
delX2 = ions[1] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[0];
ions[0] = ions[1];
ions[1] = temp;
//cout << “Vertical Ions swapped” << endl;
}
}
if (ionCounter == 2)
{
delX1 = ions[2] - DiPrev;
delX2 = ions[3] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[2];
ions[2] = ions[3];
ions[3] = temp;
//cout << “Horizontal Ions swapped” << endl;
}
}
//now calculate impact parameter
if(neighborFlag == 0)
{
delX = ions[ionCounter] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
else if(neighborFlag == 1)
{
double impact[13] = {0.0};
double radial[13] = {0.0};
double S[13] = {0.0};
double sumS = 0.0;
double Probability[13] = {0.0};
double rnd_candidate = 0.0;
int selected_candidate = -1;
for(int ncount = 0; ncount <= 13; ncount++)
{
delX = neighborIonsBCC[ncount] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
//scatterIonPos = neighborIonsBCC[ncount];
impact[ncount] = p;
radial[ncount] = delX.magnitude();
S[ncount] = 1 / ( pow(impact[ncount],2) * radial[ncount] );
sumS += S[ncount];
//general scheme of selecting the neighbor ion
// if(p < pmax[LL])
// {
// scatterIonPos = neighborIonsBCC[ncount];
// //cout << “Neighbor “ << ncount << “ is selected” << endl;
// break;
// }
}
for(int ncount = 0; ncount <= 13; ncount++)
{
Probability[ncount] = S[ncount] / sumS;
}
//print out the probability array
cout << endl;
for(int ncount = 0; ncount <= 13; ncount++)
{
//cout << Probability[ncount] << “ “;
infoStream << Probability[ncount] << “ “;
}
infoStream << endl;
//cout << endl;
//random number between 0 and 1
rnd_candidate = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) );
//cout << “rand_candidate: “ << rnd_candidate << endl;
//choose the candidate for scattering
selected_candidate = whichNonUniformBin(rnd_candidate, Probability, 13);
//cout << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate <<
endl;
infoStream << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate
<< endl;
//assign the scatterIonPos variable to the selected neighbor
scatterIonPos = neighborIonsBCC[selected_candidate];
//cout << “Scattering Ion Position: “; scatterIonPos.printVector();
//find the essential quantities for the selected neighbor
delX = neighborIonsBCC[selected_candidate] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
//find eps and b using fi[LL][nn], using nn that I was supposed to find from above
//here im deliberately using nn = 1
eps = fi[LL][1] * e;
b = p / ai[LL][1];
if (eps > 10) //rutherford scattering
{
s2 = 1.0 / (1.0 + (1.0 + b * (1.0 + b)) * pow((2.0 * eps * b), 2) );
c2 = 1.0 - s2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
else //magic formula
{
r = b;
rr = -2.7 * log(eps * b);
if (rr >= b)//note >= sign instead < in trim85
{
rr = -2.7 * log(eps * rr);
if (rr >= b)//note >= sign instead < in trim85
{
r = rr;
}
}
//do while loop that replaces line 330 loop
do
{
ex1 = 0.18175 * exp(-3.1998 * r);
ex2 = 0.50986 * exp(-0.94229 * r);
ex3 = 0.28022 * exp(-0.4029 * r);
ex4 = 0.028171 * exp(-0.20162 * r);
v = (ex1 + ex2 + ex3 + ex4) / r;
v1 = -(v + 3.1998 * ex1 + 0.94229 * ex2 + 0.4029 * ex3 + 0.20162 * ex4) / r;
fr = b * b / r + v * r / eps - r;
fr1 = -b * b / (r * r) + (v + v1 * r) / eps - 1.0;
q = fr / fr1;
r = r - q;
}
while( (Abs(q / r)) > 0.001 );
roc = -2.0 * (eps - v) / v1;
sqe = sqrt(eps);
//5 parameter magic scattering calculation
//below is for universal potential
cc = (0.011615 + sqe) / (0.0071222 + sqe);
aa = 2.0 * eps * (1.0 + (0.99229 / sqe) ) * ( pow(b, cc) );
ff = ( sqrt(aa * aa + 1.0) - aa) * ( (9.3066 + eps) / (14.813 + eps) );
delta = (r - b) * aa * ff / (ff + 1.0);
co = (b + delta + roc) / (r + roc);
c2 = co * co;
s2 = 1.0 - c2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
Theta = acos(ct);
//we are done finding theta (in CM system). So calculate all other quantities.
//find separation and the separation vector.
phi = (Pi - Theta) / 2;
sep = p / tan(phi);
sepVector = lambda * sep;
//find theta in laboratory frame - psi
psi = atan(st / (ct + my[LL][1] ) );
//note: change my[LL][1] to my[LL][nn] when the above section is fixed.
if (psi < 0 ) psi = psi + Pi; //should I do this for crystals?
//find Di, the scattering point vector
Di = DiPrev + delX + pVector - sepVector;
//find new direction of motion
lambdaPrime = lambda * cos(psi) + pUnitVector * sin(psi);
lambdaPrime.normalize();
//find length of step, ls = distance of Di from DiPrev
ls = Di.getDistance(DiPrev);
//find energy lost due to electronic stopping, dee
ie = (int)(e/e0kev+0.5); //should it be 0.5? or less so that ie <=1000?
see = se[LL][ie];
if (e < e0kev) see = se[LL][1] * sqrt(e/e0kev);
dee = ls * see;
// den = energy transferred to recoil
den = ec[LL][1] * s2 * e; //note: I am using ec[LL][1] here instead of [LL][nn].
//cout << “den = “ << den << “, dee = “ << dee << endl;
infoStream << “den = “ << den << “, dee = “ << dee << endl;
e = e - den - dee;
//cout << endl<< “current ion energy: “ << e << endl;
if (dee > maximum) maximum = dee;
pl = pl + ls - tau;
//write the ion position to output file
outStream << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
if((ic%30)==0)
{
//cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
}
//determine which scatter plot Di’s x value belongs to.
//output the y and z coordinates to scatter plot file accordingly.
for(int cc = 0; cc <= numScatterPlotBins; cc++)
{
if( Di.x >= (scatterPlot[cc]) )
{
crystalMuonY = Di.y - translationY;
crystalMuonZ = Di.z - translationZ;
//cout << “scatter plot “ << ct << “: “ << scatterPlot[ct] << endl;
scatterStream << scatterPlot[cc] << “\t” << crystalMuonY << “\t” <<
crystalMuonZ << endl;
//set scatterPlot[ss] to a big number
scatterPlot[cc] = 10000;
//break out of this for loop
break;
}
}
//determine if Di is in the channeling region.
//insideChannel = Di.isInsidePolygon(ionsOrdered, 4);
//break out of parent loop if not inside the channel
if(insideChannel == 0)
{
cout << “Ion “ << ih << “ is out of Channel” << endl;
cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
break;
}
//determine which layer the next collision will be in
if (Di.x < 0.0) //particle is backscattered
{
backscattered = 1; //cout << “ion number “ << ih << “ backscattered.” << endl;
infoStream << “ion number “ << ih << “ backscattered.” << endl;
ib = ib + 1;
eb = eb + e;
break; //break out of ‘mother do loop’ and continue with the next session of
for loop.
}
//here we set the current or next layer the particle will be in
for (w = 1; w <= Layer; w++)
{
if ( (Di.x <= xx[w]) && (w == 1) )
{
LL = 1;
//cout << endl<<”ion is in layer “ << LL << endl;
break;
//break out of this For loop and go check if the particle is transmitted.
}
else if ( (Di.x <= xx[w]) && (Di.x > xx[w-1]) )
{
LL = w;
//cout << “ion is in layer “ << LL <<endl;
break; //break out of this For loop and go check if the particle is
transmitted.
}
}
//now, check for particle transmission, i.e. whether the particle went out of the
last layer.
if(Di.x >= xx[Layer])
{
//particle is transmitted, take care of appropriate variables and break
transmitted = 1;//cout << “ion number “ << ih << “ transmitted.” << endl;
it = it + 1;
et = et + e;
ia = 57.295779 * acos(cosin) / da + 1.0;
ie = 100 * e / e0 + 1.0;
//m[ie][ia] = m[ie][ia] + 1;//note: how is this possible? ie and ia should be
integers in order to access the elements of the array m[][]. But we calculate them as
doubles here!
break; //break out of the ‘mother’ do loop
}
//now take care of ionCounter and other variables for the next scattering
if(neighborFlag == 0)
{
if(ionCounter == 3)
{
//ionCounter = 0;
neighborFlag = 1;
scatterIonPos = ions[3];
//cout << endl << “got out of first two layers” << endl;
}
else
{
ionCounter++;
}
}
if(neighborFlag == 1)
{
//cout << “Updating Neighbor Ions” << endl;
neighborIonsBCC[0] = scatterIonPos + lx - ly + lz;
neighborIonsBCC[1] = scatterIonPos + lx + ly + lz;
neighborIonsBCC[2] = scatterIonPos + lx + ly - lz;
neighborIonsBCC[3] = scatterIonPos + lx - ly - lz;
neighborIonsBCC[4] = scatterIonPos + lx * 2;
neighborIonsBCC[5] = scatterIonPos - lx - ly - lz;
neighborIonsBCC[6] = scatterIonPos - lx + ly - lz;
neighborIonsBCC[7] = scatterIonPos - lx + ly + lz;
neighborIonsBCC[8] = scatterIonPos - lx - ly + lz;
neighborIonsBCC[9] = scatterIonPos + lz * 2;
neighborIonsBCC[10] = scatterIonPos - lz * 2;
neighborIonsBCC[11] = scatterIonPos + ly * 2;
neighborIonsBCC[12] = scatterIonPos - ly * 2;
neighborIonsBCC[13] = scatterIonPos - lx * 2;
}
//set DiPrev to Di
DiPrev = Di;
//update current lambda to lambdaPrime
lambda = lambdaPrime;
//now the while condition of the mother do loop checks if the particle has lesser
energy than our lowest energy limit, ef.
}
while(e > ef);
//since we are out of the mother do loop now, the particle must have come to a
stop. So, increase the final particle distributions if the particle has not been
transmitted or backscattered.
if( ((transmitted == 0)) && ((backscattered == 0)) && ((insideChannel == 1)) )
{
ip = (int)(pl/cw + 1.0);
if(ip > 100) ip = 100;
//ipl[ip] = ipl[ip] + 1;
xsum = xsum + Di.x;
//my own bin function
selectedXBin = whichBin(Di.x, xx[Layer], numXBin);
//write the selected bin to the output file
//outStream << selectedXBin << endl;
//cout << x << endl << xx[Layer] << endl << numXBin << endl << selectedXBin;
xBin[selectedXBin] = xBin[selectedXBin] + 1;
//print final x value for plotting histogram
//cout << “ion “ << ih << “ final x: “ << Di.x << endl;
infoStream << “ion “ << ih << “ final x: “ << Di.x << endl;
//cout << Di.x << “,”;
rangeStream << Di.x << endl;
plsum = plsum + pl;
icsum = icsum + ic;
//ipl is the ion path length - the total avg. distance the ion travels
regardless of direction before it comes to stop
}
//that brings us to the end of one ion’s journey, now go to next ion by going back
to the for loop’s beginning..
}
//and this ends the monte carlo loop function. Take care of necessary structures and
variables that need to be cleared/deleted
outStream.close();
scatterStream.close();
infoStream << “Number of Backscattered Ions: “ << ib << endl;
infoStream.close();
rangeStream.close();
}
int whichNonUniformBin(double e, double arr[], int numBins)
{
double low = 0, high = arr[0];
if((e>=low) && (e<high))
return 0;
else
{
for(int i = 0; i < numBins; i++)
{
low += arr[i];
high += arr[i+1];
//cout << “\tlow: “ << low << “, high:” << high << endl;
if((e>=low) && (e<high))
return i;
}
}
}
135
//============================================================================
// Name : monte.cpp
// Author : Nazmus Saquib
// Version :
// Copyright :
// Description : BCA code in C++
//============================================================================
#include “Globals.h”
#include “scoef.h”
#include “rstop.h”
#include “muscle_bca.h”
#include “vectorGeometry.h”
const int numXBin = 100;
const int numIons = 1;
int xBin[numXBin+1] = {0};
int selectedXBin = 0;
double rho[4]={0.0};
int n[]={0,0,0,0};
double e0kev, m1, cw, ed, latticeConst;
int z1, hn, iy, nowout;
double dx[3] = {0.0};
int zt[3][7] = {0};
double mt[3][7] = {0.};
double t[3][7] = {0.};
int Layer; //use this for number of layers rather than the L in the program;
//remember this cannot be set to 0. Other loops/arrays may start from
//0, but keep this >= 1;
//the arrays..
double my[3][7]= {0},
ai[3][7]= {0},
fi[3][7]= {0},
ec[3][7]= {0},
io[3][7]= {0},
k[3]= {0},
kl[3][7]= {0};
double vf[3][7]= {0},
mu[3]= {0},
ioniz[3]= {0},
h[3]= {0},
xx[3]= {0},
m2[3]= {0.0},
z2[3]= {0},
c[3]= {0},
epsbk[3]= {0},
arho[3]= {0};
double a[3]= {0},
f[3]= {0},
lm[3]= {0},
pmax[3]= {0},
fd[3]= {0},
kd[3]= {0},
sbk[3]= {0},
lf[3]= {0},
yy[8]= {0};
double se[3][1000]= {0.0},
seo[1000]= {0.0},
epsdg[3]= {0.0};
double ls = 0., lo = 0., maximum = 0.;
double xsum = 0, x2sum = 0, x3sum = 0, x4sum = 0, plsum = 0, pl2sum = 0;
double avex = 0, vari = 0, sigma = 0, v = 0, v2 = 0, Gamma = 0, beta = 0, y = 0, avepl
= 0, sigpl = 0, avecol = 0;
int i = 0, j = 0;
int ib = 0, it = 0;
double eb = 0.0, et = 0.0;
int icsum = 0;
double y2sum = 0, xy2sum = 0, x2y2su = 0, y4sum = 0;
double tau = 0;
int iii = -1;
//my dummy vars
int w; double q;
//my customized data structures or vars
scoefData scoefz1;
rstopData rstp;
//these vars (continuing from this line) are added later as needed, vars that were not
declared in the initialization of trim85 but showed up in the middle.
double e0, ef;
int iz;
double alfa, alpha;
double tmin, da;
double L0;
int iz1;
double ee;
int izt;
double nh;
double epso;
int ih;
double e;
//boolean for keeping track of a particle being transmitted or backscattered
int transmitted = 0;
int backscattered = 0;
//boolean for keeping track of channeling
int insideChannel = 1;
//boolean for determining whether to scatter from neighbor atoms
int neighborFlag = 0;
//main function
int main()
{
cout << “Initializing” << endl;
Initialize(“IronInput.dat”);
calculateAvgMassOfLayer();
getStoppingForTarget();
setInitialConditions();
MonteCarlo();
/* *********************** Testing Ground for arrays and variables
******************** */
for (w = 1; w <= 8; w++) cout << “\t “ << yy[w];
for (w = 1; w <= 3; w++) cout << “\n\t “ << xx[w];
cout << “CW or L0: “ << L0;
//(trouble! The values of n[] elements are changing like crazy)
cout << endl << n[0] << “\t” << n[1] << “\t” << n[2] << “\t” << n[3] << endl;
cout << endl << rho[0] << “\t” << rho[1] << “\t” << rho[2] << “\t” << rho[3] <<
“\t” << rho[4] << endl;
//test z2[], m2[] arrays
for (w = 1; w <= Layer; w++) cout << “\t “ << z2[w];
for (w = 1; w <= Layer; w++) cout << “\n\t “ << m2[w];
//test the se values
cout << endl << se[1][1000] << “ “ << se[2][1000] << “ “ << se[3][1000] << endl;
//test the se[] values by printing 10th element from the array (to be implemented)
//for (w = 1; w <= 100; w++)
//{
//for (int sss = 1; sss <= 50; sss++)
//{
//cout << “\t” << mpart[w][sss];
//}
//}
/* *********************** End of Testing Ground ************************** */
cout << endl;
//Now print values of each bin in xBin
//for (w = 1; w <= numXBin; w++) cout << xBin[w] << “,”;
//print final x values
cout << endl;
cout << “Number of Backscattered Ions: “ << ib << endl;
cout << “Number of Transmitted Ions: “ << it << endl;
return 0;
}
//end of main
//Helper functions follow from here
//initialize variables and setup each layer over here
void Initialize(char* filename)
{
//Read command file
ifstream instream;
instream.open(filename,ios::in);
cout << filename;
if (!instream)
{
exitOnError(filename);
}
instream >> e0kev >> z1 >> m1 >> latticeConst >> hn >> cw >> ed >> iy >> nowout;
instream >> dx[1] >> rho[1];
instream >> zt[1][1] >> mt[1][1] >> t[1][1];
instream >> n[1];
instream >> dx[2] >> rho[2];
instream >> zt[2][1] >> mt[2][1] >> t[2][1];
instream >> n[2];
instream >> dx[3] >> rho[3];
instream >> zt[3][1] >> mt[3][1] >> t[3][1];
instream >> n[3];
for (w = 0; w <= 3; w++)
{ if (n[w] != 1) n[w] = 1; }
instream.close();
Layer = 3;
//done with primary (crude) setup, off to reading scoef.dat file
iz = z1;
getstructScoef(iz, scoefz1, “scoef1.dat”); //used to get pcoef data yy in trim85
//so we put the values in yy here immediately
for (w = 1; w <= 8; w++)
{ yy[w] = scoefz1.pcoef[w]; }
//note: although yy turns out to be just a dummy array
e0 = e0kev*1000; //convert to ev.
if (ed == 0.) ed = 25.0;
ef = Max(5.0, e0kev*0.1);
//alfa = angle of incidence, alpha = radian of alfa
alfa = 0.;
alpha = alfa*Pi/180;
tmin = 5.0;
tau = 0.0;
da = 3.0;
if (iy == 0) iy = 16381;
//now calculate the total depth of each layer = xx(l), and grid spacing cw
xx[1] = dx[1];
for (w = 2; w <= 3; w++) { xx[w] = dx[w] + xx[w-1]; }
if (cw == 0) cw = 0.01*xx[3];
L0 = cw;
//take care of any custom variable or struct I made
rstp.vfermi = 0.0; //set this to 0. for the time being (see log for explanation)
//now, off to avg mass of layer in the next void function
}
//avg mass and atomic number of each layer
void calculateAvgMassOfLayer()
{
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
h[LL] = h[LL] + t[LL][w];
//cout << “testing here..” << rstp.vfermi << endl;
}
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
t[LL][w] = t[LL][w]/h[LL];
m2[LL] = m2[LL] + t[LL][w] * mt[LL][w];
z2[LL] = z2[LL] + t[LL][w] * zt[LL][w];
//note: z2 wont be an integer once t has a value other than 1.0??
//so are we calculating average atomic number here? why?
}
}
//done with this, off to finding electronic stopping powers in the next function
}
void getStoppingForTarget()
{
iz1 = z1; ee = 0;
for (int LL = 1; LL <= Layer; LL++)
{
arho[LL] = rho[LL] * 0.6022/(m2[LL]);
mu[LL] = m1/(m2[LL]);
int ii = n[LL];
for (int nn = 1; nn <= ii; nn++)
{
//set rstp.se[1..1000] = 0. Clear it for the next loop
for (w = 1; w <= 1000; w++)
{ rstp.se[w] = 0.; }
izt = zt[LL][nn];
//calling getrstop now. units, lfctr, vfermi = 1 (doesnt matter)
getrStop(iz1, izt, e0kev, 1, 1., 1., rstp); //rstp defined in header
//set this anyway, though I dont calculate this in RSTOP
vf[LL][nn] = rstp.vfermi; //which is just set 0 in the struct def.
for (w = 1; w <= 1000; w++)
{
se[LL][w] = se[LL][w] + rstp.se[w] * t[LL][nn] * arho[LL];
}
}
}
//now, off to setting up initial conditions next function
}
void setInitialConditions()
{
nh = hn; //number of histories
for (int LL = 1; LL <= Layer; LL++)
{
a[LL] = 0.5292 * 0.8853 / ( pow(z1, 0.23) + pow(z2[LL], 0.23) );
//now calculate the mean flight path with the conditions given in trim85
f[LL] = a[LL] * m2[LL] / ( z1 * z2[LL] * 14.4 * (m1 + m2[LL] ) );
epso = e0 * f[LL];
epsdg[LL] = tmin * f[LL] * pow( (1.0 + mu[LL]) , 2) / (4.0 * mu[LL]);
fd[LL] = 0.01 * pow( z2[LL], (-7.0/3.0) );
kd[LL] = 0.1334 * pow ( z2[LL], (2.0/3.0) ) / sqrt( m2[LL] );
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
my[LL][w] = m1/mt[LL][w];
ec[LL][w] = 4.0 * my[LL][w] / pow( ( 1.0 + my[LL][w] ), 2);
ai[LL][w] = 0.5292 * 0.8853 / ( pow(z1,0.23) + pow(zt[LL][w],0.23) );
fi[LL][w] = ai[LL][w] * mt[LL][w] / ( z1 * zt[LL][w] * 14.4 * ( m1 + mt[LL][w] ) );
}
}
cout << “Setup finished. Starting Monte Carlo Loops..”;
//off to monte carlo loop in next routine
}
void MonteCarlo()
{
//custom variables and arrays for this section
double e;
double cosin = 0.0, siny = 0.0, sine = 0.0, cosy = 0.0;
double pl = 0.0;
int ic;
int LL = 1;
double eps;
double eeg;
double p;
double b;
int ie, ia; //not sure if ie or ia should be double. They are used to access elements
of the m[][] array at some point
double see;
double dee;
double s2, c2, ct, st;
double r, rr;
double ex1, ex2, ex3, ex4;
double v, v1;
double fr, fr1;
double q;
double roc, sqe;
double cc, aa, ff;
double delta, co;
double den;
double phi, psi;
double x1;
int ip;
//variables for crystal calculations
double sep = 0.0;
int ionCounter = 0;
double p1, p2;
double Theta = 0.0;
double rTheta = 0.0, rPhi = 0.0;
double thetaThreshold = 0.5;
double crystalMuonY = 0.0, crystalMuonZ = 0.0;
//amount of translations in y and z axes
double translationY = 0.0, translationZ = 0.0;
//Scatter Plot variables
const int numScatterPlotBins = 5;
double scatterPlot[numScatterPlotBins + 1] = {0.0};
//Vector declarations
//lattice constant of Target (input from file)
double latticeConstant = latticeConst;
Vector3 ions[4];
Vector3 ionsOrdered[4];
Vector3 neighborIonsBCC[14];
Vector3 neighborIonsFCC[14];
Vector3 ionTranslationY(0,translationY,0);
Vector3 ionTranslationZ(0,0,translationZ);
Vector3 unitzplus, unitzminus, unityplus, unityminus, unitxplus, unitxminus;
unitzplus.z = 1;
unitzminus.z = -1;
unityplus.y = 1;
unityminus.y = -1;
unitxplus.x = 1;
unitxminus.x = -1;
Vector3 initialDirection(1,0,0);
Vector3 d;
d.x = 1;
d *= latticeConstant/2;
Vector3 lx(latticeConstant/2, 0, 0);
Vector3 ly(0, latticeConstant/2, 0);
Vector3 lz(0, 0, latticeConstant/2);
Vector3 lambda;
Vector3 lambdaPrime;
Vector3 pVector;
Vector3 pUnitVector;
Vector3 sepVector;
Vector3 Di;
Vector3 DiPrev;
//Vector3 DiPrevToDi;
Vector3 delX;
Vector3 delX1, delX2;
Vector3 dummy1, dummy2, temp;
Vector3 scatterIonPos;
//initialize the random number generator
srand(time(NULL));
//open file to write output
ofstream outStream;
outStream.open(“coords0.txt”);
if(outStream.fail())
{
exitOnError(“Could not open Output file”);
}
//write basic information in the output file
//number of ions, ion energy, total depth, depth of each layer
outStream << nh << “\t” << e0kev << “\t” << xx[Layer] << “\t” << dx[1] << “\t”
<< dx[2] << “\t” << dx[3] << endl;
//open scatter plot file to write current Y and Z coordinates of muons at designated
intervals
ofstream scatterStream;
scatterStream.open(“scatterOut1.txt”);
if(scatterStream.fail())
{
exitOnError(“Could not open Scatter Plot Output file”);
}
//open range distribution file to write final X coordinates of muons
ofstream rangeStream;
rangeStream.open(“rangeOut1.txt”);
if(rangeStream.fail())
{
exitOnError(“Could not open Range Distribution Output file”);
}
//Open general information dump file
ofstream infoStream;
infoStream.open(“info1.txt”);
if(infoStream.fail())
{
exitOnError(“Could not open general information Output file”);
}
//Entering the target
//First set up for the top layer
for (ih = 1; ih <= nh; ih++)
{
avex = xsum / Max(1.0, (float)(ih - ib - it - 1));
if (talk == 2) cout << “Average ion range so far: “ << avex << “ angstroms.”
<<endl;
if (talk > 2) cout << “Now starting ion number “ << ih << endl;
e = e0;
//set scatterPlot array (the intervals)
scatterPlot[0] = 10;
scatterPlot[1] = 30;
scatterPlot[2] = 50;
scatterPlot[3] = 100;
scatterPlot[4] = 150;
scatterPlot[5] = 200;
/*
for(int ccc = 0; ccc <= numScatterPlotBins; ccc++)
{
cout << “scatter plot “ << ccc << “: “ << scatterPlot[ccc] << endl;
}
*/
//Initial Ion Positions
ions[0] = d + ionTranslationZ + unitzminus * (latticeConstant/2);
ions[1] = d + ionTranslationZ + unitzplus * (latticeConstant/2);
ions[2] = d * 2 + ionTranslationY + unityminus * (latticeConstant/2);
ions[3] = d * 2 + ionTranslationY + unityplus * (latticeConstant/2);
//Create a polygon that resides on the lateral axes.
//The points are put on anticlockwise order, which is important for
//testing whether the test point lies on this polygon
ionsOrdered[0] = ions[0];
ionsOrdered[1] = ions[2];
ionsOrdered[2] = ions[1];
ionsOrdered[3] = ions[3];
//generate random theta and phi angles.
rTheta = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * thetaThreshold;
rPhi = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * 2 * Pi;
//find corresponding x, y and z components of the direction vector.
//radius of the direction vector is 1
initialDirection.x = cos(rTheta);
initialDirection.z = sin(rTheta) * cos(rPhi);
initialDirection.y = sin(rTheta) * sin(rPhi);
//set the counter to 0 for a new ion
ionCounter = 0;
pl = 0.0;
ic = 0;
//set initial DiPrev - the origin
DiPrev.x = 0.0; DiPrev.y = 0.0; DiPrev.z = 0.0;
//set initial lambda, the direction of motion. Normalize it.
lambda.clear();
lambda = initialDirection;
lambda.normalize();
//set initial delX to origin
delX.clear();
//clear the dummy delX vectors, set them to origin
delX1.clear();
delX2.clear();
dummy1.clear();
dummy2.clear();
temp.clear();
LL = 1;
//set transmitted and backscattered to false
transmitted = 0;
backscattered = 0;
//set channeling to true
insideChannel = 1;
neighborFlag = 0;
//write the initial coordinates to the output file
outStream << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << endl << “Initial: “;
//cout << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << “r1 = “ << r1 << endl;
//cycle for each collision until the energy of the particle becomes too low, or
the particle backscatters, or it goes out of the last layer (transmission)
//needs a do while loop here,
//which I will mention as the ‘mother loop’ from now.
do
{
ic = ic + 1;
eps = e * f[LL];
eeg = sqrt(eps*epsdg[LL]);
//pmax[LL] = a[LL] / (eeg + sqrt(eeg) + 0.125 * pow( eeg, 0.1) );
pmax[LL] = sqrt(3) * (latticeConstant / 2) * 0.7;
//Calculate impact parameter and choose the atom to scatter from.
//Do this for ion pairs 0,1 and 2,3.
if (ionCounter == 0)
{
delX1 = ions[0] - DiPrev;
delX2 = ions[1] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[0];
ions[0] = ions[1];
ions[1] = temp;
//cout << “Vertical Ions swapped” << endl;
}
}
if (ionCounter == 2)
{
delX1 = ions[2] - DiPrev;
delX2 = ions[3] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[2];
ions[2] = ions[3];
ions[3] = temp;
//cout << “Horizontal Ions swapped” << endl;
}
}
//now calculate impact parameter
if(neighborFlag == 0)
{
delX = ions[ionCounter] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
else if(neighborFlag == 1)
{
double impact[13] = {0.0};
double radial[13] = {0.0};
double S[13] = {0.0};
double sumS = 0.0;
double Probability[13] = {0.0};
double rnd_candidate = 0.0;
int selected_candidate = -1;
for(int ncount = 0; ncount <= 13; ncount++)
{
delX = neighborIonsBCC[ncount] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
//scatterIonPos = neighborIonsBCC[ncount];
impact[ncount] = p;
radial[ncount] = delX.magnitude();
S[ncount] = 1 / ( pow(impact[ncount],2) * radial[ncount] );
sumS += S[ncount];
//general scheme of selecting the neighbor ion
// if(p < pmax[LL])
// {
// scatterIonPos = neighborIonsBCC[ncount];
// //cout << “Neighbor “ << ncount << “ is selected” << endl;
// break;
// }
}
for(int ncount = 0; ncount <= 13; ncount++)
{
Probability[ncount] = S[ncount] / sumS;
}
//print out the probability array
cout << endl;
for(int ncount = 0; ncount <= 13; ncount++)
{
//cout << Probability[ncount] << “ “;
infoStream << Probability[ncount] << “ “;
}
infoStream << endl;
//cout << endl;
//random number between 0 and 1
rnd_candidate = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) );
//cout << “rand_candidate: “ << rnd_candidate << endl;
//choose the candidate for scattering
selected_candidate = whichNonUniformBin(rnd_candidate, Probability, 13);
//cout << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate <<
endl;
infoStream << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate
<< endl;
//assign the scatterIonPos variable to the selected neighbor
scatterIonPos = neighborIonsBCC[selected_candidate];
//cout << “Scattering Ion Position: “; scatterIonPos.printVector();
//find the essential quantities for the selected neighbor
delX = neighborIonsBCC[selected_candidate] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
//find eps and b using fi[LL][nn], using nn that I was supposed to find from above
//here im deliberately using nn = 1
eps = fi[LL][1] * e;
b = p / ai[LL][1];
if (eps > 10) //rutherford scattering
{
s2 = 1.0 / (1.0 + (1.0 + b * (1.0 + b)) * pow((2.0 * eps * b), 2) );
c2 = 1.0 - s2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
else //magic formula
{
r = b;
rr = -2.7 * log(eps * b);
if (rr >= b)//note >= sign instead < in trim85
{
rr = -2.7 * log(eps * rr);
if (rr >= b)//note >= sign instead < in trim85
{
r = rr;
}
}
//do while loop that replaces line 330 loop
do
{
ex1 = 0.18175 * exp(-3.1998 * r);
ex2 = 0.50986 * exp(-0.94229 * r);
ex3 = 0.28022 * exp(-0.4029 * r);
ex4 = 0.028171 * exp(-0.20162 * r);
v = (ex1 + ex2 + ex3 + ex4) / r;
v1 = -(v + 3.1998 * ex1 + 0.94229 * ex2 + 0.4029 * ex3 + 0.20162 * ex4) / r;
fr = b * b / r + v * r / eps - r;
fr1 = -b * b / (r * r) + (v + v1 * r) / eps - 1.0;
q = fr / fr1;
r = r - q;
}
while( (Abs(q / r)) > 0.001 );
roc = -2.0 * (eps - v) / v1;
sqe = sqrt(eps);
//5 parameter magic scattering calculation
//below is for universal potential
cc = (0.011615 + sqe) / (0.0071222 + sqe);
aa = 2.0 * eps * (1.0 + (0.99229 / sqe) ) * ( pow(b, cc) );
ff = ( sqrt(aa * aa + 1.0) - aa) * ( (9.3066 + eps) / (14.813 + eps) );
delta = (r - b) * aa * ff / (ff + 1.0);
co = (b + delta + roc) / (r + roc);
c2 = co * co;
s2 = 1.0 - c2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
Theta = acos(ct);
//we are done finding theta (in CM system). So calculate all other quantities.
//find separation and the separation vector.
phi = (Pi - Theta) / 2;
sep = p / tan(phi);
sepVector = lambda * sep;
//find theta in laboratory frame - psi
psi = atan(st / (ct + my[LL][1] ) );
//note: change my[LL][1] to my[LL][nn] when the above section is fixed.
if (psi < 0 ) psi = psi + Pi; //should I do this for crystals?
//find Di, the scattering point vector
Di = DiPrev + delX + pVector - sepVector;
//find new direction of motion
lambdaPrime = lambda * cos(psi) + pUnitVector * sin(psi);
lambdaPrime.normalize();
//find length of step, ls = distance of Di from DiPrev
ls = Di.getDistance(DiPrev);
//find energy lost due to electronic stopping, dee
ie = (int)(e/e0kev+0.5); //should it be 0.5? or less so that ie <=1000?
see = se[LL][ie];
if (e < e0kev) see = se[LL][1] * sqrt(e/e0kev);
dee = ls * see;
// den = energy transferred to recoil
den = ec[LL][1] * s2 * e; //note: I am using ec[LL][1] here instead of [LL][nn].
//cout << “den = “ << den << “, dee = “ << dee << endl;
infoStream << “den = “ << den << “, dee = “ << dee << endl;
e = e - den - dee;
//cout << endl<< “current ion energy: “ << e << endl;
if (dee > maximum) maximum = dee;
pl = pl + ls - tau;
//write the ion position to output file
outStream << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
if((ic%30)==0)
{
//cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
}
//determine which scatter plot Di’s x value belongs to.
//output the y and z coordinates to scatter plot file accordingly.
for(int cc = 0; cc <= numScatterPlotBins; cc++)
{
if( Di.x >= (scatterPlot[cc]) )
{
crystalMuonY = Di.y - translationY;
crystalMuonZ = Di.z - translationZ;
//cout << “scatter plot “ << ct << “: “ << scatterPlot[ct] << endl;
scatterStream << scatterPlot[cc] << “\t” << crystalMuonY << “\t” <<
crystalMuonZ << endl;
//set scatterPlot[ss] to a big number
scatterPlot[cc] = 10000;
//break out of this for loop
break;
}
}
//determine if Di is in the channeling region.
//insideChannel = Di.isInsidePolygon(ionsOrdered, 4);
//break out of parent loop if not inside the channel
if(insideChannel == 0)
{
cout << “Ion “ << ih << “ is out of Channel” << endl;
cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
break;
}
//determine which layer the next collision will be in
if (Di.x < 0.0) //particle is backscattered
{
backscattered = 1; //cout << “ion number “ << ih << “ backscattered.” << endl;
infoStream << “ion number “ << ih << “ backscattered.” << endl;
ib = ib + 1;
eb = eb + e;
break; //break out of ‘mother do loop’ and continue with the next session of
for loop.
}
//here we set the current or next layer the particle will be in
for (w = 1; w <= Layer; w++)
{
if ( (Di.x <= xx[w]) && (w == 1) )
{
LL = 1;
//cout << endl<<”ion is in layer “ << LL << endl;
break;
//break out of this For loop and go check if the particle is transmitted.
}
else if ( (Di.x <= xx[w]) && (Di.x > xx[w-1]) )
{
LL = w;
//cout << “ion is in layer “ << LL <<endl;
break; //break out of this For loop and go check if the particle is
transmitted.
}
}
//now, check for particle transmission, i.e. whether the particle went out of the
last layer.
if(Di.x >= xx[Layer])
{
//particle is transmitted, take care of appropriate variables and break
transmitted = 1;//cout << “ion number “ << ih << “ transmitted.” << endl;
it = it + 1;
et = et + e;
ia = 57.295779 * acos(cosin) / da + 1.0;
ie = 100 * e / e0 + 1.0;
//m[ie][ia] = m[ie][ia] + 1;//note: how is this possible? ie and ia should be
integers in order to access the elements of the array m[][]. But we calculate them as
doubles here!
break; //break out of the ‘mother’ do loop
}
//now take care of ionCounter and other variables for the next scattering
if(neighborFlag == 0)
{
if(ionCounter == 3)
{
//ionCounter = 0;
neighborFlag = 1;
scatterIonPos = ions[3];
//cout << endl << “got out of first two layers” << endl;
}
else
{
ionCounter++;
}
}
if(neighborFlag == 1)
{
//cout << “Updating Neighbor Ions” << endl;
neighborIonsBCC[0] = scatterIonPos + lx - ly + lz;
neighborIonsBCC[1] = scatterIonPos + lx + ly + lz;
neighborIonsBCC[2] = scatterIonPos + lx + ly - lz;
neighborIonsBCC[3] = scatterIonPos + lx - ly - lz;
neighborIonsBCC[4] = scatterIonPos + lx * 2;
neighborIonsBCC[5] = scatterIonPos - lx - ly - lz;
neighborIonsBCC[6] = scatterIonPos - lx + ly - lz;
neighborIonsBCC[7] = scatterIonPos - lx + ly + lz;
neighborIonsBCC[8] = scatterIonPos - lx - ly + lz;
neighborIonsBCC[9] = scatterIonPos + lz * 2;
neighborIonsBCC[10] = scatterIonPos - lz * 2;
neighborIonsBCC[11] = scatterIonPos + ly * 2;
neighborIonsBCC[12] = scatterIonPos - ly * 2;
neighborIonsBCC[13] = scatterIonPos - lx * 2;
}
//set DiPrev to Di
DiPrev = Di;
//update current lambda to lambdaPrime
lambda = lambdaPrime;
//now the while condition of the mother do loop checks if the particle has lesser
energy than our lowest energy limit, ef.
}
while(e > ef);
//since we are out of the mother do loop now, the particle must have come to a
stop. So, increase the final particle distributions if the particle has not been
transmitted or backscattered.
if( ((transmitted == 0)) && ((backscattered == 0)) && ((insideChannel == 1)) )
{
ip = (int)(pl/cw + 1.0);
if(ip > 100) ip = 100;
//ipl[ip] = ipl[ip] + 1;
xsum = xsum + Di.x;
//my own bin function
selectedXBin = whichBin(Di.x, xx[Layer], numXBin);
//write the selected bin to the output file
//outStream << selectedXBin << endl;
//cout << x << endl << xx[Layer] << endl << numXBin << endl << selectedXBin;
xBin[selectedXBin] = xBin[selectedXBin] + 1;
//print final x value for plotting histogram
//cout << “ion “ << ih << “ final x: “ << Di.x << endl;
infoStream << “ion “ << ih << “ final x: “ << Di.x << endl;
//cout << Di.x << “,”;
rangeStream << Di.x << endl;
plsum = plsum + pl;
icsum = icsum + ic;
//ipl is the ion path length - the total avg. distance the ion travels
regardless of direction before it comes to stop
}
//that brings us to the end of one ion’s journey, now go to next ion by going back
to the for loop’s beginning..
}
//and this ends the monte carlo loop function. Take care of necessary structures and
variables that need to be cleared/deleted
outStream.close();
scatterStream.close();
infoStream << “Number of Backscattered Ions: “ << ib << endl;
infoStream.close();
rangeStream.close();
}
int whichNonUniformBin(double e, double arr[], int numBins)
{
double low = 0, high = arr[0];
if((e>=low) && (e<high))
return 0;
else
{
for(int i = 0; i < numBins; i++)
{
low += arr[i];
high += arr[i+1];
//cout << “\tlow: “ << low << “, high:” << high << endl;
if((e>=low) && (e<high))
return i;
}
}
}
136
//============================================================================
// Name : monte.cpp
// Author : Nazmus Saquib
// Version :
// Copyright :
// Description : BCA code in C++
//============================================================================
#include “Globals.h”
#include “scoef.h”
#include “rstop.h”
#include “muscle_bca.h”
#include “vectorGeometry.h”
const int numXBin = 100;
const int numIons = 1;
int xBin[numXBin+1] = {0};
int selectedXBin = 0;
double rho[4]={0.0};
int n[]={0,0,0,0};
double e0kev, m1, cw, ed, latticeConst;
int z1, hn, iy, nowout;
double dx[3] = {0.0};
int zt[3][7] = {0};
double mt[3][7] = {0.};
double t[3][7] = {0.};
int Layer; //use this for number of layers rather than the L in the program;
//remember this cannot be set to 0. Other loops/arrays may start from
//0, but keep this >= 1;
//the arrays..
double my[3][7]= {0},
ai[3][7]= {0},
fi[3][7]= {0},
ec[3][7]= {0},
io[3][7]= {0},
k[3]= {0},
kl[3][7]= {0};
double vf[3][7]= {0},
mu[3]= {0},
ioniz[3]= {0},
h[3]= {0},
xx[3]= {0},
m2[3]= {0.0},
z2[3]= {0},
c[3]= {0},
epsbk[3]= {0},
arho[3]= {0};
double a[3]= {0},
f[3]= {0},
lm[3]= {0},
pmax[3]= {0},
fd[3]= {0},
kd[3]= {0},
sbk[3]= {0},
lf[3]= {0},
yy[8]= {0};
double se[3][1000]= {0.0},
seo[1000]= {0.0},
epsdg[3]= {0.0};
double ls = 0., lo = 0., maximum = 0.;
double xsum = 0, x2sum = 0, x3sum = 0, x4sum = 0, plsum = 0, pl2sum = 0;
double avex = 0, vari = 0, sigma = 0, v = 0, v2 = 0, Gamma = 0, beta = 0, y = 0, avepl
= 0, sigpl = 0, avecol = 0;
int i = 0, j = 0;
int ib = 0, it = 0;
double eb = 0.0, et = 0.0;
int icsum = 0;
double y2sum = 0, xy2sum = 0, x2y2su = 0, y4sum = 0;
double tau = 0;
int iii = -1;
//my dummy vars
int w; double q;
//my customized data structures or vars
scoefData scoefz1;
rstopData rstp;
//these vars (continuing from this line) are added later as needed, vars that were not
declared in the initialization of trim85 but showed up in the middle.
double e0, ef;
int iz;
double alfa, alpha;
double tmin, da;
double L0;
int iz1;
double ee;
int izt;
double nh;
double epso;
int ih;
double e;
//boolean for keeping track of a particle being transmitted or backscattered
int transmitted = 0;
int backscattered = 0;
//boolean for keeping track of channeling
int insideChannel = 1;
//boolean for determining whether to scatter from neighbor atoms
int neighborFlag = 0;
//main function
int main()
{
cout << “Initializing” << endl;
Initialize(“IronInput.dat”);
calculateAvgMassOfLayer();
getStoppingForTarget();
setInitialConditions();
MonteCarlo();
/* *********************** Testing Ground for arrays and variables
******************** */
for (w = 1; w <= 8; w++) cout << “\t “ << yy[w];
for (w = 1; w <= 3; w++) cout << “\n\t “ << xx[w];
cout << “CW or L0: “ << L0;
//(trouble! The values of n[] elements are changing like crazy)
cout << endl << n[0] << “\t” << n[1] << “\t” << n[2] << “\t” << n[3] << endl;
cout << endl << rho[0] << “\t” << rho[1] << “\t” << rho[2] << “\t” << rho[3] <<
“\t” << rho[4] << endl;
//test z2[], m2[] arrays
for (w = 1; w <= Layer; w++) cout << “\t “ << z2[w];
for (w = 1; w <= Layer; w++) cout << “\n\t “ << m2[w];
//test the se values
cout << endl << se[1][1000] << “ “ << se[2][1000] << “ “ << se[3][1000] << endl;
//test the se[] values by printing 10th element from the array (to be implemented)
//for (w = 1; w <= 100; w++)
//{
//for (int sss = 1; sss <= 50; sss++)
//{
//cout << “\t” << mpart[w][sss];
//}
//}
/* *********************** End of Testing Ground ************************** */
cout << endl;
//Now print values of each bin in xBin
//for (w = 1; w <= numXBin; w++) cout << xBin[w] << “,”;
//print final x values
cout << endl;
cout << “Number of Backscattered Ions: “ << ib << endl;
cout << “Number of Transmitted Ions: “ << it << endl;
return 0;
}
//end of main
//Helper functions follow from here
//initialize variables and setup each layer over here
void Initialize(char* filename)
{
//Read command file
ifstream instream;
instream.open(filename,ios::in);
cout << filename;
if (!instream)
{
exitOnError(filename);
}
instream >> e0kev >> z1 >> m1 >> latticeConst >> hn >> cw >> ed >> iy >> nowout;
instream >> dx[1] >> rho[1];
instream >> zt[1][1] >> mt[1][1] >> t[1][1];
instream >> n[1];
instream >> dx[2] >> rho[2];
instream >> zt[2][1] >> mt[2][1] >> t[2][1];
instream >> n[2];
instream >> dx[3] >> rho[3];
instream >> zt[3][1] >> mt[3][1] >> t[3][1];
instream >> n[3];
for (w = 0; w <= 3; w++)
{ if (n[w] != 1) n[w] = 1; }
instream.close();
Layer = 3;
//done with primary (crude) setup, off to reading scoef.dat file
iz = z1;
getstructScoef(iz, scoefz1, “scoef1.dat”); //used to get pcoef data yy in trim85
//so we put the values in yy here immediately
for (w = 1; w <= 8; w++)
{ yy[w] = scoefz1.pcoef[w]; }
//note: although yy turns out to be just a dummy array
e0 = e0kev*1000; //convert to ev.
if (ed == 0.) ed = 25.0;
ef = Max(5.0, e0kev*0.1);
//alfa = angle of incidence, alpha = radian of alfa
alfa = 0.;
alpha = alfa*Pi/180;
tmin = 5.0;
tau = 0.0;
da = 3.0;
if (iy == 0) iy = 16381;
//now calculate the total depth of each layer = xx(l), and grid spacing cw
xx[1] = dx[1];
for (w = 2; w <= 3; w++) { xx[w] = dx[w] + xx[w-1]; }
if (cw == 0) cw = 0.01*xx[3];
L0 = cw;
//take care of any custom variable or struct I made
rstp.vfermi = 0.0; //set this to 0. for the time being (see log for explanation)
//now, off to avg mass of layer in the next void function
}
//avg mass and atomic number of each layer
void calculateAvgMassOfLayer()
{
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
h[LL] = h[LL] + t[LL][w];
//cout << “testing here..” << rstp.vfermi << endl;
}
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
t[LL][w] = t[LL][w]/h[LL];
m2[LL] = m2[LL] + t[LL][w] * mt[LL][w];
z2[LL] = z2[LL] + t[LL][w] * zt[LL][w];
//note: z2 wont be an integer once t has a value other than 1.0??
//so are we calculating average atomic number here? why?
}
}
//done with this, off to finding electronic stopping powers in the next function
}
void getStoppingForTarget()
{
iz1 = z1; ee = 0;
for (int LL = 1; LL <= Layer; LL++)
{
arho[LL] = rho[LL] * 0.6022/(m2[LL]);
mu[LL] = m1/(m2[LL]);
int ii = n[LL];
for (int nn = 1; nn <= ii; nn++)
{
//set rstp.se[1..1000] = 0. Clear it for the next loop
for (w = 1; w <= 1000; w++)
{ rstp.se[w] = 0.; }
izt = zt[LL][nn];
//calling getrstop now. units, lfctr, vfermi = 1 (doesnt matter)
getrStop(iz1, izt, e0kev, 1, 1., 1., rstp); //rstp defined in header
//set this anyway, though I dont calculate this in RSTOP
vf[LL][nn] = rstp.vfermi; //which is just set 0 in the struct def.
for (w = 1; w <= 1000; w++)
{
se[LL][w] = se[LL][w] + rstp.se[w] * t[LL][nn] * arho[LL];
}
}
}
//now, off to setting up initial conditions next function
}
void setInitialConditions()
{
nh = hn; //number of histories
for (int LL = 1; LL <= Layer; LL++)
{
a[LL] = 0.5292 * 0.8853 / ( pow(z1, 0.23) + pow(z2[LL], 0.23) );
//now calculate the mean flight path with the conditions given in trim85
f[LL] = a[LL] * m2[LL] / ( z1 * z2[LL] * 14.4 * (m1 + m2[LL] ) );
epso = e0 * f[LL];
epsdg[LL] = tmin * f[LL] * pow( (1.0 + mu[LL]) , 2) / (4.0 * mu[LL]);
fd[LL] = 0.01 * pow( z2[LL], (-7.0/3.0) );
kd[LL] = 0.1334 * pow ( z2[LL], (2.0/3.0) ) / sqrt( m2[LL] );
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
my[LL][w] = m1/mt[LL][w];
ec[LL][w] = 4.0 * my[LL][w] / pow( ( 1.0 + my[LL][w] ), 2);
ai[LL][w] = 0.5292 * 0.8853 / ( pow(z1,0.23) + pow(zt[LL][w],0.23) );
fi[LL][w] = ai[LL][w] * mt[LL][w] / ( z1 * zt[LL][w] * 14.4 * ( m1 + mt[LL][w] ) );
}
}
cout << “Setup finished. Starting Monte Carlo Loops..”;
//off to monte carlo loop in next routine
}
void MonteCarlo()
{
//custom variables and arrays for this section
double e;
double cosin = 0.0, siny = 0.0, sine = 0.0, cosy = 0.0;
double pl = 0.0;
int ic;
int LL = 1;
double eps;
double eeg;
double p;
double b;
int ie, ia; //not sure if ie or ia should be double. They are used to access elements
of the m[][] array at some point
double see;
double dee;
double s2, c2, ct, st;
double r, rr;
double ex1, ex2, ex3, ex4;
double v, v1;
double fr, fr1;
double q;
double roc, sqe;
double cc, aa, ff;
double delta, co;
double den;
double phi, psi;
double x1;
int ip;
//variables for crystal calculations
double sep = 0.0;
int ionCounter = 0;
double p1, p2;
double Theta = 0.0;
double rTheta = 0.0, rPhi = 0.0;
double thetaThreshold = 0.5;
double crystalMuonY = 0.0, crystalMuonZ = 0.0;
//amount of translations in y and z axes
double translationY = 0.0, translationZ = 0.0;
//Scatter Plot variables
const int numScatterPlotBins = 5;
double scatterPlot[numScatterPlotBins + 1] = {0.0};
//Vector declarations
//lattice constant of Target (input from file)
double latticeConstant = latticeConst;
Vector3 ions[4];
Vector3 ionsOrdered[4];
Vector3 neighborIonsBCC[14];
Vector3 neighborIonsFCC[14];
Vector3 ionTranslationY(0,translationY,0);
Vector3 ionTranslationZ(0,0,translationZ);
Vector3 unitzplus, unitzminus, unityplus, unityminus, unitxplus, unitxminus;
unitzplus.z = 1;
unitzminus.z = -1;
unityplus.y = 1;
unityminus.y = -1;
unitxplus.x = 1;
unitxminus.x = -1;
Vector3 initialDirection(1,0,0);
Vector3 d;
d.x = 1;
d *= latticeConstant/2;
Vector3 lx(latticeConstant/2, 0, 0);
Vector3 ly(0, latticeConstant/2, 0);
Vector3 lz(0, 0, latticeConstant/2);
Vector3 lambda;
Vector3 lambdaPrime;
Vector3 pVector;
Vector3 pUnitVector;
Vector3 sepVector;
Vector3 Di;
Vector3 DiPrev;
//Vector3 DiPrevToDi;
Vector3 delX;
Vector3 delX1, delX2;
Vector3 dummy1, dummy2, temp;
Vector3 scatterIonPos;
//initialize the random number generator
srand(time(NULL));
//open file to write output
ofstream outStream;
outStream.open(“coords0.txt”);
if(outStream.fail())
{
exitOnError(“Could not open Output file”);
}
//write basic information in the output file
//number of ions, ion energy, total depth, depth of each layer
outStream << nh << “\t” << e0kev << “\t” << xx[Layer] << “\t” << dx[1] << “\t”
<< dx[2] << “\t” << dx[3] << endl;
//open scatter plot file to write current Y and Z coordinates of muons at designated
intervals
ofstream scatterStream;
scatterStream.open(“scatterOut1.txt”);
if(scatterStream.fail())
{
exitOnError(“Could not open Scatter Plot Output file”);
}
//open range distribution file to write final X coordinates of muons
ofstream rangeStream;
rangeStream.open(“rangeOut1.txt”);
if(rangeStream.fail())
{
exitOnError(“Could not open Range Distribution Output file”);
}
//Open general information dump file
ofstream infoStream;
infoStream.open(“info1.txt”);
if(infoStream.fail())
{
exitOnError(“Could not open general information Output file”);
}
//Entering the target
//First set up for the top layer
for (ih = 1; ih <= nh; ih++)
{
avex = xsum / Max(1.0, (float)(ih - ib - it - 1));
if (talk == 2) cout << “Average ion range so far: “ << avex << “ angstroms.”
<<endl;
if (talk > 2) cout << “Now starting ion number “ << ih << endl;
e = e0;
//set scatterPlot array (the intervals)
scatterPlot[0] = 10;
scatterPlot[1] = 30;
scatterPlot[2] = 50;
scatterPlot[3] = 100;
scatterPlot[4] = 150;
scatterPlot[5] = 200;
/*
for(int ccc = 0; ccc <= numScatterPlotBins; ccc++)
{
cout << “scatter plot “ << ccc << “: “ << scatterPlot[ccc] << endl;
}
*/
//Initial Ion Positions
ions[0] = d + ionTranslationZ + unitzminus * (latticeConstant/2);
ions[1] = d + ionTranslationZ + unitzplus * (latticeConstant/2);
ions[2] = d * 2 + ionTranslationY + unityminus * (latticeConstant/2);
ions[3] = d * 2 + ionTranslationY + unityplus * (latticeConstant/2);
//Create a polygon that resides on the lateral axes.
//The points are put on anticlockwise order, which is important for
//testing whether the test point lies on this polygon
ionsOrdered[0] = ions[0];
ionsOrdered[1] = ions[2];
ionsOrdered[2] = ions[1];
ionsOrdered[3] = ions[3];
//generate random theta and phi angles.
rTheta = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * thetaThreshold;
rPhi = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * 2 * Pi;
//find corresponding x, y and z components of the direction vector.
//radius of the direction vector is 1
initialDirection.x = cos(rTheta);
initialDirection.z = sin(rTheta) * cos(rPhi);
initialDirection.y = sin(rTheta) * sin(rPhi);
//set the counter to 0 for a new ion
ionCounter = 0;
pl = 0.0;
ic = 0;
//set initial DiPrev - the origin
DiPrev.x = 0.0; DiPrev.y = 0.0; DiPrev.z = 0.0;
//set initial lambda, the direction of motion. Normalize it.
lambda.clear();
lambda = initialDirection;
lambda.normalize();
//set initial delX to origin
delX.clear();
//clear the dummy delX vectors, set them to origin
delX1.clear();
delX2.clear();
dummy1.clear();
dummy2.clear();
temp.clear();
LL = 1;
//set transmitted and backscattered to false
transmitted = 0;
backscattered = 0;
//set channeling to true
insideChannel = 1;
neighborFlag = 0;
//write the initial coordinates to the output file
outStream << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << endl << “Initial: “;
//cout << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << “r1 = “ << r1 << endl;
//cycle for each collision until the energy of the particle becomes too low, or
the particle backscatters, or it goes out of the last layer (transmission)
//needs a do while loop here,
//which I will mention as the ‘mother loop’ from now.
do
{
ic = ic + 1;
eps = e * f[LL];
eeg = sqrt(eps*epsdg[LL]);
//pmax[LL] = a[LL] / (eeg + sqrt(eeg) + 0.125 * pow( eeg, 0.1) );
pmax[LL] = sqrt(3) * (latticeConstant / 2) * 0.7;
//Calculate impact parameter and choose the atom to scatter from.
//Do this for ion pairs 0,1 and 2,3.
if (ionCounter == 0)
{
delX1 = ions[0] - DiPrev;
delX2 = ions[1] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[0];
ions[0] = ions[1];
ions[1] = temp;
//cout << “Vertical Ions swapped” << endl;
}
}
if (ionCounter == 2)
{
delX1 = ions[2] - DiPrev;
delX2 = ions[3] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[2];
ions[2] = ions[3];
ions[3] = temp;
//cout << “Horizontal Ions swapped” << endl;
}
}
//now calculate impact parameter
if(neighborFlag == 0)
{
delX = ions[ionCounter] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
else if(neighborFlag == 1)
{
double impact[13] = {0.0};
double radial[13] = {0.0};
double S[13] = {0.0};
double sumS = 0.0;
double Probability[13] = {0.0};
double rnd_candidate = 0.0;
int selected_candidate = -1;
for(int ncount = 0; ncount <= 13; ncount++)
{
delX = neighborIonsBCC[ncount] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
//scatterIonPos = neighborIonsBCC[ncount];
impact[ncount] = p;
radial[ncount] = delX.magnitude();
S[ncount] = 1 / ( pow(impact[ncount],2) * radial[ncount] );
sumS += S[ncount];
//general scheme of selecting the neighbor ion
// if(p < pmax[LL])
// {
// scatterIonPos = neighborIonsBCC[ncount];
// //cout << “Neighbor “ << ncount << “ is selected” << endl;
// break;
// }
}
for(int ncount = 0; ncount <= 13; ncount++)
{
Probability[ncount] = S[ncount] / sumS;
}
//print out the probability array
cout << endl;
for(int ncount = 0; ncount <= 13; ncount++)
{
//cout << Probability[ncount] << “ “;
infoStream << Probability[ncount] << “ “;
}
infoStream << endl;
//cout << endl;
//random number between 0 and 1
rnd_candidate = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) );
//cout << “rand_candidate: “ << rnd_candidate << endl;
//choose the candidate for scattering
selected_candidate = whichNonUniformBin(rnd_candidate, Probability, 13);
//cout << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate <<
endl;
infoStream << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate
<< endl;
//assign the scatterIonPos variable to the selected neighbor
scatterIonPos = neighborIonsBCC[selected_candidate];
//cout << “Scattering Ion Position: “; scatterIonPos.printVector();
//find the essential quantities for the selected neighbor
delX = neighborIonsBCC[selected_candidate] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
//find eps and b using fi[LL][nn], using nn that I was supposed to find from above
//here im deliberately using nn = 1
eps = fi[LL][1] * e;
b = p / ai[LL][1];
if (eps > 10) //rutherford scattering
{
s2 = 1.0 / (1.0 + (1.0 + b * (1.0 + b)) * pow((2.0 * eps * b), 2) );
c2 = 1.0 - s2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
else //magic formula
{
r = b;
rr = -2.7 * log(eps * b);
if (rr >= b)//note >= sign instead < in trim85
{
rr = -2.7 * log(eps * rr);
if (rr >= b)//note >= sign instead < in trim85
{
r = rr;
}
}
//do while loop that replaces line 330 loop
do
{
ex1 = 0.18175 * exp(-3.1998 * r);
ex2 = 0.50986 * exp(-0.94229 * r);
ex3 = 0.28022 * exp(-0.4029 * r);
ex4 = 0.028171 * exp(-0.20162 * r);
v = (ex1 + ex2 + ex3 + ex4) / r;
v1 = -(v + 3.1998 * ex1 + 0.94229 * ex2 + 0.4029 * ex3 + 0.20162 * ex4) / r;
fr = b * b / r + v * r / eps - r;
fr1 = -b * b / (r * r) + (v + v1 * r) / eps - 1.0;
q = fr / fr1;
r = r - q;
}
while( (Abs(q / r)) > 0.001 );
roc = -2.0 * (eps - v) / v1;
sqe = sqrt(eps);
//5 parameter magic scattering calculation
//below is for universal potential
cc = (0.011615 + sqe) / (0.0071222 + sqe);
aa = 2.0 * eps * (1.0 + (0.99229 / sqe) ) * ( pow(b, cc) );
ff = ( sqrt(aa * aa + 1.0) - aa) * ( (9.3066 + eps) / (14.813 + eps) );
delta = (r - b) * aa * ff / (ff + 1.0);
co = (b + delta + roc) / (r + roc);
c2 = co * co;
s2 = 1.0 - c2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
Theta = acos(ct);
//we are done finding theta (in CM system). So calculate all other quantities.
//find separation and the separation vector.
phi = (Pi - Theta) / 2;
sep = p / tan(phi);
sepVector = lambda * sep;
//find theta in laboratory frame - psi
psi = atan(st / (ct + my[LL][1] ) );
//note: change my[LL][1] to my[LL][nn] when the above section is fixed.
if (psi < 0 ) psi = psi + Pi; //should I do this for crystals?
//find Di, the scattering point vector
Di = DiPrev + delX + pVector - sepVector;
//find new direction of motion
lambdaPrime = lambda * cos(psi) + pUnitVector * sin(psi);
lambdaPrime.normalize();
//find length of step, ls = distance of Di from DiPrev
ls = Di.getDistance(DiPrev);
//find energy lost due to electronic stopping, dee
ie = (int)(e/e0kev+0.5); //should it be 0.5? or less so that ie <=1000?
see = se[LL][ie];
if (e < e0kev) see = se[LL][1] * sqrt(e/e0kev);
dee = ls * see;
// den = energy transferred to recoil
den = ec[LL][1] * s2 * e; //note: I am using ec[LL][1] here instead of [LL][nn].
//cout << “den = “ << den << “, dee = “ << dee << endl;
infoStream << “den = “ << den << “, dee = “ << dee << endl;
e = e - den - dee;
//cout << endl<< “current ion energy: “ << e << endl;
if (dee > maximum) maximum = dee;
pl = pl + ls - tau;
//write the ion position to output file
outStream << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
if((ic%30)==0)
{
//cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
}
//determine which scatter plot Di’s x value belongs to.
//output the y and z coordinates to scatter plot file accordingly.
for(int cc = 0; cc <= numScatterPlotBins; cc++)
{
if( Di.x >= (scatterPlot[cc]) )
{
crystalMuonY = Di.y - translationY;
crystalMuonZ = Di.z - translationZ;
//cout << “scatter plot “ << ct << “: “ << scatterPlot[ct] << endl;
scatterStream << scatterPlot[cc] << “\t” << crystalMuonY << “\t” <<
crystalMuonZ << endl;
//set scatterPlot[ss] to a big number
scatterPlot[cc] = 10000;
//break out of this for loop
break;
}
}
//determine if Di is in the channeling region.
//insideChannel = Di.isInsidePolygon(ionsOrdered, 4);
//break out of parent loop if not inside the channel
if(insideChannel == 0)
{
cout << “Ion “ << ih << “ is out of Channel” << endl;
cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
break;
}
//determine which layer the next collision will be in
if (Di.x < 0.0) //particle is backscattered
{
backscattered = 1; //cout << “ion number “ << ih << “ backscattered.” << endl;
infoStream << “ion number “ << ih << “ backscattered.” << endl;
ib = ib + 1;
eb = eb + e;
break; //break out of ‘mother do loop’ and continue with the next session of
for loop.
}
//here we set the current or next layer the particle will be in
for (w = 1; w <= Layer; w++)
{
if ( (Di.x <= xx[w]) && (w == 1) )
{
LL = 1;
//cout << endl<<”ion is in layer “ << LL << endl;
break;
//break out of this For loop and go check if the particle is transmitted.
}
else if ( (Di.x <= xx[w]) && (Di.x > xx[w-1]) )
{
LL = w;
//cout << “ion is in layer “ << LL <<endl;
break; //break out of this For loop and go check if the particle is
transmitted.
}
}
//now, check for particle transmission, i.e. whether the particle went out of the
last layer.
if(Di.x >= xx[Layer])
{
//particle is transmitted, take care of appropriate variables and break
transmitted = 1;//cout << “ion number “ << ih << “ transmitted.” << endl;
it = it + 1;
et = et + e;
ia = 57.295779 * acos(cosin) / da + 1.0;
ie = 100 * e / e0 + 1.0;
//m[ie][ia] = m[ie][ia] + 1;//note: how is this possible? ie and ia should be
integers in order to access the elements of the array m[][]. But we calculate them as
doubles here!
break; //break out of the ‘mother’ do loop
}
//now take care of ionCounter and other variables for the next scattering
if(neighborFlag == 0)
{
if(ionCounter == 3)
{
//ionCounter = 0;
neighborFlag = 1;
scatterIonPos = ions[3];
//cout << endl << “got out of first two layers” << endl;
}
else
{
ionCounter++;
}
}
if(neighborFlag == 1)
{
//cout << “Updating Neighbor Ions” << endl;
neighborIonsBCC[0] = scatterIonPos + lx - ly + lz;
neighborIonsBCC[1] = scatterIonPos + lx + ly + lz;
neighborIonsBCC[2] = scatterIonPos + lx + ly - lz;
neighborIonsBCC[3] = scatterIonPos + lx - ly - lz;
neighborIonsBCC[4] = scatterIonPos + lx * 2;
neighborIonsBCC[5] = scatterIonPos - lx - ly - lz;
neighborIonsBCC[6] = scatterIonPos - lx + ly - lz;
neighborIonsBCC[7] = scatterIonPos - lx + ly + lz;
neighborIonsBCC[8] = scatterIonPos - lx - ly + lz;
neighborIonsBCC[9] = scatterIonPos + lz * 2;
neighborIonsBCC[10] = scatterIonPos - lz * 2;
neighborIonsBCC[11] = scatterIonPos + ly * 2;
neighborIonsBCC[12] = scatterIonPos - ly * 2;
neighborIonsBCC[13] = scatterIonPos - lx * 2;
}
//set DiPrev to Di
DiPrev = Di;
//update current lambda to lambdaPrime
lambda = lambdaPrime;
//now the while condition of the mother do loop checks if the particle has lesser
energy than our lowest energy limit, ef.
}
while(e > ef);
//since we are out of the mother do loop now, the particle must have come to a
stop. So, increase the final particle distributions if the particle has not been
transmitted or backscattered.
if( ((transmitted == 0)) && ((backscattered == 0)) && ((insideChannel == 1)) )
{
ip = (int)(pl/cw + 1.0);
if(ip > 100) ip = 100;
//ipl[ip] = ipl[ip] + 1;
xsum = xsum + Di.x;
//my own bin function
selectedXBin = whichBin(Di.x, xx[Layer], numXBin);
//write the selected bin to the output file
//outStream << selectedXBin << endl;
//cout << x << endl << xx[Layer] << endl << numXBin << endl << selectedXBin;
xBin[selectedXBin] = xBin[selectedXBin] + 1;
//print final x value for plotting histogram
//cout << “ion “ << ih << “ final x: “ << Di.x << endl;
infoStream << “ion “ << ih << “ final x: “ << Di.x << endl;
//cout << Di.x << “,”;
rangeStream << Di.x << endl;
plsum = plsum + pl;
icsum = icsum + ic;
//ipl is the ion path length - the total avg. distance the ion travels
regardless of direction before it comes to stop
}
//that brings us to the end of one ion’s journey, now go to next ion by going back
to the for loop’s beginning..
}
//and this ends the monte carlo loop function. Take care of necessary structures and
variables that need to be cleared/deleted
outStream.close();
scatterStream.close();
infoStream << “Number of Backscattered Ions: “ << ib << endl;
infoStream.close();
rangeStream.close();
}
int whichNonUniformBin(double e, double arr[], int numBins)
{
double low = 0, high = arr[0];
if((e>=low) && (e<high))
return 0;
else
{
for(int i = 0; i < numBins; i++)
{
low += arr[i];
high += arr[i+1];
//cout << “\tlow: “ << low << “, high:” << high << endl;
if((e>=low) && (e<high))
return i;
}
}
}
137
//============================================================================
// Name : monte.cpp
// Author : Nazmus Saquib
// Version :
// Copyright :
// Description : BCA code in C++
//============================================================================
#include “Globals.h”
#include “scoef.h”
#include “rstop.h”
#include “muscle_bca.h”
#include “vectorGeometry.h”
const int numXBin = 100;
const int numIons = 1;
int xBin[numXBin+1] = {0};
int selectedXBin = 0;
double rho[4]={0.0};
int n[]={0,0,0,0};
double e0kev, m1, cw, ed, latticeConst;
int z1, hn, iy, nowout;
double dx[3] = {0.0};
int zt[3][7] = {0};
double mt[3][7] = {0.};
double t[3][7] = {0.};
int Layer; //use this for number of layers rather than the L in the program;
//remember this cannot be set to 0. Other loops/arrays may start from
//0, but keep this >= 1;
//the arrays..
double my[3][7]= {0},
ai[3][7]= {0},
fi[3][7]= {0},
ec[3][7]= {0},
io[3][7]= {0},
k[3]= {0},
kl[3][7]= {0};
double vf[3][7]= {0},
mu[3]= {0},
ioniz[3]= {0},
h[3]= {0},
xx[3]= {0},
m2[3]= {0.0},
z2[3]= {0},
c[3]= {0},
epsbk[3]= {0},
arho[3]= {0};
double a[3]= {0},
f[3]= {0},
lm[3]= {0},
pmax[3]= {0},
fd[3]= {0},
kd[3]= {0},
sbk[3]= {0},
lf[3]= {0},
yy[8]= {0};
double se[3][1000]= {0.0},
seo[1000]= {0.0},
epsdg[3]= {0.0};
double ls = 0., lo = 0., maximum = 0.;
double xsum = 0, x2sum = 0, x3sum = 0, x4sum = 0, plsum = 0, pl2sum = 0;
double avex = 0, vari = 0, sigma = 0, v = 0, v2 = 0, Gamma = 0, beta = 0, y = 0, avepl
= 0, sigpl = 0, avecol = 0;
int i = 0, j = 0;
int ib = 0, it = 0;
double eb = 0.0, et = 0.0;
int icsum = 0;
double y2sum = 0, xy2sum = 0, x2y2su = 0, y4sum = 0;
double tau = 0;
int iii = -1;
//my dummy vars
int w; double q;
//my customized data structures or vars
scoefData scoefz1;
rstopData rstp;
//these vars (continuing from this line) are added later as needed, vars that were not
declared in the initialization of trim85 but showed up in the middle.
double e0, ef;
int iz;
double alfa, alpha;
double tmin, da;
double L0;
int iz1;
double ee;
int izt;
double nh;
double epso;
int ih;
double e;
//boolean for keeping track of a particle being transmitted or backscattered
int transmitted = 0;
int backscattered = 0;
//boolean for keeping track of channeling
int insideChannel = 1;
//boolean for determining whether to scatter from neighbor atoms
int neighborFlag = 0;
//main function
int main()
{
cout << “Initializing” << endl;
Initialize(“IronInput.dat”);
calculateAvgMassOfLayer();
getStoppingForTarget();
setInitialConditions();
MonteCarlo();
/* *********************** Testing Ground for arrays and variables
******************** */
for (w = 1; w <= 8; w++) cout << “\t “ << yy[w];
for (w = 1; w <= 3; w++) cout << “\n\t “ << xx[w];
cout << “CW or L0: “ << L0;
//(trouble! The values of n[] elements are changing like crazy)
cout << endl << n[0] << “\t” << n[1] << “\t” << n[2] << “\t” << n[3] << endl;
cout << endl << rho[0] << “\t” << rho[1] << “\t” << rho[2] << “\t” << rho[3] <<
“\t” << rho[4] << endl;
//test z2[], m2[] arrays
for (w = 1; w <= Layer; w++) cout << “\t “ << z2[w];
for (w = 1; w <= Layer; w++) cout << “\n\t “ << m2[w];
//test the se values
cout << endl << se[1][1000] << “ “ << se[2][1000] << “ “ << se[3][1000] << endl;
//test the se[] values by printing 10th element from the array (to be implemented)
//for (w = 1; w <= 100; w++)
//{
//for (int sss = 1; sss <= 50; sss++)
//{
//cout << “\t” << mpart[w][sss];
//}
//}
/* *********************** End of Testing Ground ************************** */
cout << endl;
//Now print values of each bin in xBin
//for (w = 1; w <= numXBin; w++) cout << xBin[w] << “,”;
//print final x values
cout << endl;
cout << “Number of Backscattered Ions: “ << ib << endl;
cout << “Number of Transmitted Ions: “ << it << endl;
return 0;
}
//end of main
//Helper functions follow from here
//initialize variables and setup each layer over here
void Initialize(char* filename)
{
//Read command file
ifstream instream;
instream.open(filename,ios::in);
cout << filename;
if (!instream)
{
exitOnError(filename);
}
instream >> e0kev >> z1 >> m1 >> latticeConst >> hn >> cw >> ed >> iy >> nowout;
instream >> dx[1] >> rho[1];
instream >> zt[1][1] >> mt[1][1] >> t[1][1];
instream >> n[1];
instream >> dx[2] >> rho[2];
instream >> zt[2][1] >> mt[2][1] >> t[2][1];
instream >> n[2];
instream >> dx[3] >> rho[3];
instream >> zt[3][1] >> mt[3][1] >> t[3][1];
instream >> n[3];
for (w = 0; w <= 3; w++)
{ if (n[w] != 1) n[w] = 1; }
instream.close();
Layer = 3;
//done with primary (crude) setup, off to reading scoef.dat file
iz = z1;
getstructScoef(iz, scoefz1, “scoef1.dat”); //used to get pcoef data yy in trim85
//so we put the values in yy here immediately
for (w = 1; w <= 8; w++)
{ yy[w] = scoefz1.pcoef[w]; }
//note: although yy turns out to be just a dummy array
e0 = e0kev*1000; //convert to ev.
if (ed == 0.) ed = 25.0;
ef = Max(5.0, e0kev*0.1);
//alfa = angle of incidence, alpha = radian of alfa
alfa = 0.;
alpha = alfa*Pi/180;
tmin = 5.0;
tau = 0.0;
da = 3.0;
if (iy == 0) iy = 16381;
//now calculate the total depth of each layer = xx(l), and grid spacing cw
xx[1] = dx[1];
for (w = 2; w <= 3; w++) { xx[w] = dx[w] + xx[w-1]; }
if (cw == 0) cw = 0.01*xx[3];
L0 = cw;
//take care of any custom variable or struct I made
rstp.vfermi = 0.0; //set this to 0. for the time being (see log for explanation)
//now, off to avg mass of layer in the next void function
}
//avg mass and atomic number of each layer
void calculateAvgMassOfLayer()
{
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
h[LL] = h[LL] + t[LL][w];
//cout << “testing here..” << rstp.vfermi << endl;
}
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
t[LL][w] = t[LL][w]/h[LL];
m2[LL] = m2[LL] + t[LL][w] * mt[LL][w];
z2[LL] = z2[LL] + t[LL][w] * zt[LL][w];
//note: z2 wont be an integer once t has a value other than 1.0??
//so are we calculating average atomic number here? why?
}
}
//done with this, off to finding electronic stopping powers in the next function
}
void getStoppingForTarget()
{
iz1 = z1; ee = 0;
for (int LL = 1; LL <= Layer; LL++)
{
arho[LL] = rho[LL] * 0.6022/(m2[LL]);
mu[LL] = m1/(m2[LL]);
int ii = n[LL];
for (int nn = 1; nn <= ii; nn++)
{
//set rstp.se[1..1000] = 0. Clear it for the next loop
for (w = 1; w <= 1000; w++)
{ rstp.se[w] = 0.; }
izt = zt[LL][nn];
//calling getrstop now. units, lfctr, vfermi = 1 (doesnt matter)
getrStop(iz1, izt, e0kev, 1, 1., 1., rstp); //rstp defined in header
//set this anyway, though I dont calculate this in RSTOP
vf[LL][nn] = rstp.vfermi; //which is just set 0 in the struct def.
for (w = 1; w <= 1000; w++)
{
se[LL][w] = se[LL][w] + rstp.se[w] * t[LL][nn] * arho[LL];
}
}
}
//now, off to setting up initial conditions next function
}
void setInitialConditions()
{
nh = hn; //number of histories
for (int LL = 1; LL <= Layer; LL++)
{
a[LL] = 0.5292 * 0.8853 / ( pow(z1, 0.23) + pow(z2[LL], 0.23) );
//now calculate the mean flight path with the conditions given in trim85
f[LL] = a[LL] * m2[LL] / ( z1 * z2[LL] * 14.4 * (m1 + m2[LL] ) );
epso = e0 * f[LL];
epsdg[LL] = tmin * f[LL] * pow( (1.0 + mu[LL]) , 2) / (4.0 * mu[LL]);
fd[LL] = 0.01 * pow( z2[LL], (-7.0/3.0) );
kd[LL] = 0.1334 * pow ( z2[LL], (2.0/3.0) ) / sqrt( m2[LL] );
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
my[LL][w] = m1/mt[LL][w];
ec[LL][w] = 4.0 * my[LL][w] / pow( ( 1.0 + my[LL][w] ), 2);
ai[LL][w] = 0.5292 * 0.8853 / ( pow(z1,0.23) + pow(zt[LL][w],0.23) );
fi[LL][w] = ai[LL][w] * mt[LL][w] / ( z1 * zt[LL][w] * 14.4 * ( m1 + mt[LL][w] ) );
}
}
cout << “Setup finished. Starting Monte Carlo Loops..”;
//off to monte carlo loop in next routine
}
void MonteCarlo()
{
//custom variables and arrays for this section
double e;
double cosin = 0.0, siny = 0.0, sine = 0.0, cosy = 0.0;
double pl = 0.0;
int ic;
int LL = 1;
double eps;
double eeg;
double p;
double b;
int ie, ia; //not sure if ie or ia should be double. They are used to access elements
of the m[][] array at some point
double see;
double dee;
double s2, c2, ct, st;
double r, rr;
double ex1, ex2, ex3, ex4;
double v, v1;
double fr, fr1;
double q;
double roc, sqe;
double cc, aa, ff;
double delta, co;
double den;
double phi, psi;
double x1;
int ip;
//variables for crystal calculations
double sep = 0.0;
int ionCounter = 0;
double p1, p2;
double Theta = 0.0;
double rTheta = 0.0, rPhi = 0.0;
double thetaThreshold = 0.5;
double crystalMuonY = 0.0, crystalMuonZ = 0.0;
//amount of translations in y and z axes
double translationY = 0.0, translationZ = 0.0;
//Scatter Plot variables
const int numScatterPlotBins = 5;
double scatterPlot[numScatterPlotBins + 1] = {0.0};
//Vector declarations
//lattice constant of Target (input from file)
double latticeConstant = latticeConst;
Vector3 ions[4];
Vector3 ionsOrdered[4];
Vector3 neighborIonsBCC[14];
Vector3 neighborIonsFCC[14];
Vector3 ionTranslationY(0,translationY,0);
Vector3 ionTranslationZ(0,0,translationZ);
Vector3 unitzplus, unitzminus, unityplus, unityminus, unitxplus, unitxminus;
unitzplus.z = 1;
unitzminus.z = -1;
unityplus.y = 1;
unityminus.y = -1;
unitxplus.x = 1;
unitxminus.x = -1;
Vector3 initialDirection(1,0,0);
Vector3 d;
d.x = 1;
d *= latticeConstant/2;
Vector3 lx(latticeConstant/2, 0, 0);
Vector3 ly(0, latticeConstant/2, 0);
Vector3 lz(0, 0, latticeConstant/2);
Vector3 lambda;
Vector3 lambdaPrime;
Vector3 pVector;
Vector3 pUnitVector;
Vector3 sepVector;
Vector3 Di;
Vector3 DiPrev;
//Vector3 DiPrevToDi;
Vector3 delX;
Vector3 delX1, delX2;
Vector3 dummy1, dummy2, temp;
Vector3 scatterIonPos;
//initialize the random number generator
srand(time(NULL));
//open file to write output
ofstream outStream;
outStream.open(“coords0.txt”);
if(outStream.fail())
{
exitOnError(“Could not open Output file”);
}
//write basic information in the output file
//number of ions, ion energy, total depth, depth of each layer
outStream << nh << “\t” << e0kev << “\t” << xx[Layer] << “\t” << dx[1] << “\t”
<< dx[2] << “\t” << dx[3] << endl;
//open scatter plot file to write current Y and Z coordinates of muons at designated
intervals
ofstream scatterStream;
scatterStream.open(“scatterOut1.txt”);
if(scatterStream.fail())
{
exitOnError(“Could not open Scatter Plot Output file”);
}
//open range distribution file to write final X coordinates of muons
ofstream rangeStream;
rangeStream.open(“rangeOut1.txt”);
if(rangeStream.fail())
{
exitOnError(“Could not open Range Distribution Output file”);
}
//Open general information dump file
ofstream infoStream;
infoStream.open(“info1.txt”);
if(infoStream.fail())
{
exitOnError(“Could not open general information Output file”);
}
//Entering the target
//First set up for the top layer
for (ih = 1; ih <= nh; ih++)
{
avex = xsum / Max(1.0, (float)(ih - ib - it - 1));
if (talk == 2) cout << “Average ion range so far: “ << avex << “ angstroms.”
<<endl;
if (talk > 2) cout << “Now starting ion number “ << ih << endl;
e = e0;
//set scatterPlot array (the intervals)
scatterPlot[0] = 10;
scatterPlot[1] = 30;
scatterPlot[2] = 50;
scatterPlot[3] = 100;
scatterPlot[4] = 150;
scatterPlot[5] = 200;
/*
for(int ccc = 0; ccc <= numScatterPlotBins; ccc++)
{
cout << “scatter plot “ << ccc << “: “ << scatterPlot[ccc] << endl;
}
*/
//Initial Ion Positions
ions[0] = d + ionTranslationZ + unitzminus * (latticeConstant/2);
ions[1] = d + ionTranslationZ + unitzplus * (latticeConstant/2);
ions[2] = d * 2 + ionTranslationY + unityminus * (latticeConstant/2);
ions[3] = d * 2 + ionTranslationY + unityplus * (latticeConstant/2);
//Create a polygon that resides on the lateral axes.
//The points are put on anticlockwise order, which is important for
//testing whether the test point lies on this polygon
ionsOrdered[0] = ions[0];
ionsOrdered[1] = ions[2];
ionsOrdered[2] = ions[1];
ionsOrdered[3] = ions[3];
//generate random theta and phi angles.
rTheta = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * thetaThreshold;
rPhi = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * 2 * Pi;
//find corresponding x, y and z components of the direction vector.
//radius of the direction vector is 1
initialDirection.x = cos(rTheta);
initialDirection.z = sin(rTheta) * cos(rPhi);
initialDirection.y = sin(rTheta) * sin(rPhi);
//set the counter to 0 for a new ion
ionCounter = 0;
pl = 0.0;
ic = 0;
//set initial DiPrev - the origin
DiPrev.x = 0.0; DiPrev.y = 0.0; DiPrev.z = 0.0;
//set initial lambda, the direction of motion. Normalize it.
lambda.clear();
lambda = initialDirection;
lambda.normalize();
//set initial delX to origin
delX.clear();
//clear the dummy delX vectors, set them to origin
delX1.clear();
delX2.clear();
dummy1.clear();
dummy2.clear();
temp.clear();
LL = 1;
//set transmitted and backscattered to false
transmitted = 0;
backscattered = 0;
//set channeling to true
insideChannel = 1;
neighborFlag = 0;
//write the initial coordinates to the output file
outStream << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << endl << “Initial: “;
//cout << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << “r1 = “ << r1 << endl;
//cycle for each collision until the energy of the particle becomes too low, or
the particle backscatters, or it goes out of the last layer (transmission)
//needs a do while loop here,
//which I will mention as the ‘mother loop’ from now.
do
{
ic = ic + 1;
eps = e * f[LL];
eeg = sqrt(eps*epsdg[LL]);
//pmax[LL] = a[LL] / (eeg + sqrt(eeg) + 0.125 * pow( eeg, 0.1) );
pmax[LL] = sqrt(3) * (latticeConstant / 2) * 0.7;
//Calculate impact parameter and choose the atom to scatter from.
//Do this for ion pairs 0,1 and 2,3.
if (ionCounter == 0)
{
delX1 = ions[0] - DiPrev;
delX2 = ions[1] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[0];
ions[0] = ions[1];
ions[1] = temp;
//cout << “Vertical Ions swapped” << endl;
}
}
if (ionCounter == 2)
{
delX1 = ions[2] - DiPrev;
delX2 = ions[3] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[2];
ions[2] = ions[3];
ions[3] = temp;
//cout << “Horizontal Ions swapped” << endl;
}
}
//now calculate impact parameter
if(neighborFlag == 0)
{
delX = ions[ionCounter] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
else if(neighborFlag == 1)
{
double impact[13] = {0.0};
double radial[13] = {0.0};
double S[13] = {0.0};
double sumS = 0.0;
double Probability[13] = {0.0};
double rnd_candidate = 0.0;
int selected_candidate = -1;
for(int ncount = 0; ncount <= 13; ncount++)
{
delX = neighborIonsBCC[ncount] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
//scatterIonPos = neighborIonsBCC[ncount];
impact[ncount] = p;
radial[ncount] = delX.magnitude();
S[ncount] = 1 / ( pow(impact[ncount],2) * radial[ncount] );
sumS += S[ncount];
//general scheme of selecting the neighbor ion
// if(p < pmax[LL])
// {
// scatterIonPos = neighborIonsBCC[ncount];
// //cout << “Neighbor “ << ncount << “ is selected” << endl;
// break;
// }
}
for(int ncount = 0; ncount <= 13; ncount++)
{
Probability[ncount] = S[ncount] / sumS;
}
//print out the probability array
cout << endl;
for(int ncount = 0; ncount <= 13; ncount++)
{
//cout << Probability[ncount] << “ “;
infoStream << Probability[ncount] << “ “;
}
infoStream << endl;
//cout << endl;
//random number between 0 and 1
rnd_candidate = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) );
//cout << “rand_candidate: “ << rnd_candidate << endl;
//choose the candidate for scattering
selected_candidate = whichNonUniformBin(rnd_candidate, Probability, 13);
//cout << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate <<
endl;
infoStream << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate
<< endl;
//assign the scatterIonPos variable to the selected neighbor
scatterIonPos = neighborIonsBCC[selected_candidate];
//cout << “Scattering Ion Position: “; scatterIonPos.printVector();
//find the essential quantities for the selected neighbor
delX = neighborIonsBCC[selected_candidate] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
//find eps and b using fi[LL][nn], using nn that I was supposed to find from above
//here im deliberately using nn = 1
eps = fi[LL][1] * e;
b = p / ai[LL][1];
if (eps > 10) //rutherford scattering
{
s2 = 1.0 / (1.0 + (1.0 + b * (1.0 + b)) * pow((2.0 * eps * b), 2) );
c2 = 1.0 - s2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
else //magic formula
{
r = b;
rr = -2.7 * log(eps * b);
if (rr >= b)//note >= sign instead < in trim85
{
rr = -2.7 * log(eps * rr);
if (rr >= b)//note >= sign instead < in trim85
{
r = rr;
}
}
//do while loop that replaces line 330 loop
do
{
ex1 = 0.18175 * exp(-3.1998 * r);
ex2 = 0.50986 * exp(-0.94229 * r);
ex3 = 0.28022 * exp(-0.4029 * r);
ex4 = 0.028171 * exp(-0.20162 * r);
v = (ex1 + ex2 + ex3 + ex4) / r;
v1 = -(v + 3.1998 * ex1 + 0.94229 * ex2 + 0.4029 * ex3 + 0.20162 * ex4) / r;
fr = b * b / r + v * r / eps - r;
fr1 = -b * b / (r * r) + (v + v1 * r) / eps - 1.0;
q = fr / fr1;
r = r - q;
}
while( (Abs(q / r)) > 0.001 );
roc = -2.0 * (eps - v) / v1;
sqe = sqrt(eps);
//5 parameter magic scattering calculation
//below is for universal potential
cc = (0.011615 + sqe) / (0.0071222 + sqe);
aa = 2.0 * eps * (1.0 + (0.99229 / sqe) ) * ( pow(b, cc) );
ff = ( sqrt(aa * aa + 1.0) - aa) * ( (9.3066 + eps) / (14.813 + eps) );
delta = (r - b) * aa * ff / (ff + 1.0);
co = (b + delta + roc) / (r + roc);
c2 = co * co;
s2 = 1.0 - c2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
Theta = acos(ct);
//we are done finding theta (in CM system). So calculate all other quantities.
//find separation and the separation vector.
phi = (Pi - Theta) / 2;
sep = p / tan(phi);
sepVector = lambda * sep;
//find theta in laboratory frame - psi
psi = atan(st / (ct + my[LL][1] ) );
//note: change my[LL][1] to my[LL][nn] when the above section is fixed.
if (psi < 0 ) psi = psi + Pi; //should I do this for crystals?
//find Di, the scattering point vector
Di = DiPrev + delX + pVector - sepVector;
//find new direction of motion
lambdaPrime = lambda * cos(psi) + pUnitVector * sin(psi);
lambdaPrime.normalize();
//find length of step, ls = distance of Di from DiPrev
ls = Di.getDistance(DiPrev);
//find energy lost due to electronic stopping, dee
ie = (int)(e/e0kev+0.5); //should it be 0.5? or less so that ie <=1000?
see = se[LL][ie];
if (e < e0kev) see = se[LL][1] * sqrt(e/e0kev);
dee = ls * see;
// den = energy transferred to recoil
den = ec[LL][1] * s2 * e; //note: I am using ec[LL][1] here instead of [LL][nn].
//cout << “den = “ << den << “, dee = “ << dee << endl;
infoStream << “den = “ << den << “, dee = “ << dee << endl;
e = e - den - dee;
//cout << endl<< “current ion energy: “ << e << endl;
if (dee > maximum) maximum = dee;
pl = pl + ls - tau;
//write the ion position to output file
outStream << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
if((ic%30)==0)
{
//cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
}
//determine which scatter plot Di’s x value belongs to.
//output the y and z coordinates to scatter plot file accordingly.
for(int cc = 0; cc <= numScatterPlotBins; cc++)
{
if( Di.x >= (scatterPlot[cc]) )
{
crystalMuonY = Di.y - translationY;
crystalMuonZ = Di.z - translationZ;
//cout << “scatter plot “ << ct << “: “ << scatterPlot[ct] << endl;
scatterStream << scatterPlot[cc] << “\t” << crystalMuonY << “\t” <<
crystalMuonZ << endl;
//set scatterPlot[ss] to a big number
scatterPlot[cc] = 10000;
//break out of this for loop
break;
}
}
//determine if Di is in the channeling region.
//insideChannel = Di.isInsidePolygon(ionsOrdered, 4);
//break out of parent loop if not inside the channel
if(insideChannel == 0)
{
cout << “Ion “ << ih << “ is out of Channel” << endl;
cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
break;
}
//determine which layer the next collision will be in
if (Di.x < 0.0) //particle is backscattered
{
backscattered = 1; //cout << “ion number “ << ih << “ backscattered.” << endl;
infoStream << “ion number “ << ih << “ backscattered.” << endl;
ib = ib + 1;
eb = eb + e;
break; //break out of ‘mother do loop’ and continue with the next session of
for loop.
}
//here we set the current or next layer the particle will be in
for (w = 1; w <= Layer; w++)
{
if ( (Di.x <= xx[w]) && (w == 1) )
{
LL = 1;
//cout << endl<<”ion is in layer “ << LL << endl;
break;
//break out of this For loop and go check if the particle is transmitted.
}
else if ( (Di.x <= xx[w]) && (Di.x > xx[w-1]) )
{
LL = w;
//cout << “ion is in layer “ << LL <<endl;
break; //break out of this For loop and go check if the particle is
transmitted.
}
}
//now, check for particle transmission, i.e. whether the particle went out of the
last layer.
if(Di.x >= xx[Layer])
{
//particle is transmitted, take care of appropriate variables and break
transmitted = 1;//cout << “ion number “ << ih << “ transmitted.” << endl;
it = it + 1;
et = et + e;
ia = 57.295779 * acos(cosin) / da + 1.0;
ie = 100 * e / e0 + 1.0;
//m[ie][ia] = m[ie][ia] + 1;//note: how is this possible? ie and ia should be
integers in order to access the elements of the array m[][]. But we calculate them as
doubles here!
break; //break out of the ‘mother’ do loop
}
//now take care of ionCounter and other variables for the next scattering
if(neighborFlag == 0)
{
if(ionCounter == 3)
{
//ionCounter = 0;
neighborFlag = 1;
scatterIonPos = ions[3];
//cout << endl << “got out of first two layers” << endl;
}
else
{
ionCounter++;
}
}
if(neighborFlag == 1)
{
//cout << “Updating Neighbor Ions” << endl;
neighborIonsBCC[0] = scatterIonPos + lx - ly + lz;
neighborIonsBCC[1] = scatterIonPos + lx + ly + lz;
neighborIonsBCC[2] = scatterIonPos + lx + ly - lz;
neighborIonsBCC[3] = scatterIonPos + lx - ly - lz;
neighborIonsBCC[4] = scatterIonPos + lx * 2;
neighborIonsBCC[5] = scatterIonPos - lx - ly - lz;
neighborIonsBCC[6] = scatterIonPos - lx + ly - lz;
neighborIonsBCC[7] = scatterIonPos - lx + ly + lz;
neighborIonsBCC[8] = scatterIonPos - lx - ly + lz;
neighborIonsBCC[9] = scatterIonPos + lz * 2;
neighborIonsBCC[10] = scatterIonPos - lz * 2;
neighborIonsBCC[11] = scatterIonPos + ly * 2;
neighborIonsBCC[12] = scatterIonPos - ly * 2;
neighborIonsBCC[13] = scatterIonPos - lx * 2;
}
//set DiPrev to Di
DiPrev = Di;
//update current lambda to lambdaPrime
lambda = lambdaPrime;
//now the while condition of the mother do loop checks if the particle has lesser
energy than our lowest energy limit, ef.
}
while(e > ef);
//since we are out of the mother do loop now, the particle must have come to a
stop. So, increase the final particle distributions if the particle has not been
transmitted or backscattered.
if( ((transmitted == 0)) && ((backscattered == 0)) && ((insideChannel == 1)) )
{
ip = (int)(pl/cw + 1.0);
if(ip > 100) ip = 100;
//ipl[ip] = ipl[ip] + 1;
xsum = xsum + Di.x;
//my own bin function
selectedXBin = whichBin(Di.x, xx[Layer], numXBin);
//write the selected bin to the output file
//outStream << selectedXBin << endl;
//cout << x << endl << xx[Layer] << endl << numXBin << endl << selectedXBin;
xBin[selectedXBin] = xBin[selectedXBin] + 1;
//print final x value for plotting histogram
//cout << “ion “ << ih << “ final x: “ << Di.x << endl;
infoStream << “ion “ << ih << “ final x: “ << Di.x << endl;
//cout << Di.x << “,”;
rangeStream << Di.x << endl;
plsum = plsum + pl;
icsum = icsum + ic;
//ipl is the ion path length - the total avg. distance the ion travels
regardless of direction before it comes to stop
}
//that brings us to the end of one ion’s journey, now go to next ion by going back
to the for loop’s beginning..
}
//and this ends the monte carlo loop function. Take care of necessary structures and
variables that need to be cleared/deleted
outStream.close();
scatterStream.close();
infoStream << “Number of Backscattered Ions: “ << ib << endl;
infoStream.close();
rangeStream.close();
}
int whichNonUniformBin(double e, double arr[], int numBins)
{
double low = 0, high = arr[0];
if((e>=low) && (e<high))
return 0;
else
{
for(int i = 0; i < numBins; i++)
{
low += arr[i];
high += arr[i+1];
//cout << “\tlow: “ << low << “, high:” << high << endl;
if((e>=low) && (e<high))
return i;
}
}
}
138
//============================================================================
// Name : monte.cpp
// Author : Nazmus Saquib
// Version :
// Copyright :
// Description : BCA code in C++
//============================================================================
#include “Globals.h”
#include “scoef.h”
#include “rstop.h”
#include “muscle_bca.h”
#include “vectorGeometry.h”
const int numXBin = 100;
const int numIons = 1;
int xBin[numXBin+1] = {0};
int selectedXBin = 0;
double rho[4]={0.0};
int n[]={0,0,0,0};
double e0kev, m1, cw, ed, latticeConst;
int z1, hn, iy, nowout;
double dx[3] = {0.0};
int zt[3][7] = {0};
double mt[3][7] = {0.};
double t[3][7] = {0.};
int Layer; //use this for number of layers rather than the L in the program;
//remember this cannot be set to 0. Other loops/arrays may start from
//0, but keep this >= 1;
//the arrays..
double my[3][7]= {0},
ai[3][7]= {0},
fi[3][7]= {0},
ec[3][7]= {0},
io[3][7]= {0},
k[3]= {0},
kl[3][7]= {0};
double vf[3][7]= {0},
mu[3]= {0},
ioniz[3]= {0},
h[3]= {0},
xx[3]= {0},
m2[3]= {0.0},
z2[3]= {0},
c[3]= {0},
epsbk[3]= {0},
arho[3]= {0};
double a[3]= {0},
f[3]= {0},
lm[3]= {0},
pmax[3]= {0},
fd[3]= {0},
kd[3]= {0},
sbk[3]= {0},
lf[3]= {0},
yy[8]= {0};
double se[3][1000]= {0.0},
seo[1000]= {0.0},
epsdg[3]= {0.0};
double ls = 0., lo = 0., maximum = 0.;
double xsum = 0, x2sum = 0, x3sum = 0, x4sum = 0, plsum = 0, pl2sum = 0;
double avex = 0, vari = 0, sigma = 0, v = 0, v2 = 0, Gamma = 0, beta = 0, y = 0, avepl
= 0, sigpl = 0, avecol = 0;
int i = 0, j = 0;
int ib = 0, it = 0;
double eb = 0.0, et = 0.0;
int icsum = 0;
double y2sum = 0, xy2sum = 0, x2y2su = 0, y4sum = 0;
double tau = 0;
int iii = -1;
//my dummy vars
int w; double q;
//my customized data structures or vars
scoefData scoefz1;
rstopData rstp;
//these vars (continuing from this line) are added later as needed, vars that were not
declared in the initialization of trim85 but showed up in the middle.
double e0, ef;
int iz;
double alfa, alpha;
double tmin, da;
double L0;
int iz1;
double ee;
int izt;
double nh;
double epso;
int ih;
double e;
//boolean for keeping track of a particle being transmitted or backscattered
int transmitted = 0;
int backscattered = 0;
//boolean for keeping track of channeling
int insideChannel = 1;
//boolean for determining whether to scatter from neighbor atoms
int neighborFlag = 0;
//main function
int main()
{
cout << “Initializing” << endl;
Initialize(“IronInput.dat”);
calculateAvgMassOfLayer();
getStoppingForTarget();
setInitialConditions();
MonteCarlo();
/* *********************** Testing Ground for arrays and variables
******************** */
for (w = 1; w <= 8; w++) cout << “\t “ << yy[w];
for (w = 1; w <= 3; w++) cout << “\n\t “ << xx[w];
cout << “CW or L0: “ << L0;
//(trouble! The values of n[] elements are changing like crazy)
cout << endl << n[0] << “\t” << n[1] << “\t” << n[2] << “\t” << n[3] << endl;
cout << endl << rho[0] << “\t” << rho[1] << “\t” << rho[2] << “\t” << rho[3] <<
“\t” << rho[4] << endl;
//test z2[], m2[] arrays
for (w = 1; w <= Layer; w++) cout << “\t “ << z2[w];
for (w = 1; w <= Layer; w++) cout << “\n\t “ << m2[w];
//test the se values
cout << endl << se[1][1000] << “ “ << se[2][1000] << “ “ << se[3][1000] << endl;
//test the se[] values by printing 10th element from the array (to be implemented)
//for (w = 1; w <= 100; w++)
//{
//for (int sss = 1; sss <= 50; sss++)
//{
//cout << “\t” << mpart[w][sss];
//}
//}
/* *********************** End of Testing Ground ************************** */
cout << endl;
//Now print values of each bin in xBin
//for (w = 1; w <= numXBin; w++) cout << xBin[w] << “,”;
//print final x values
cout << endl;
cout << “Number of Backscattered Ions: “ << ib << endl;
cout << “Number of Transmitted Ions: “ << it << endl;
return 0;
}
//end of main
//Helper functions follow from here
//initialize variables and setup each layer over here
void Initialize(char* filename)
{
//Read command file
ifstream instream;
instream.open(filename,ios::in);
cout << filename;
if (!instream)
{
exitOnError(filename);
}
instream >> e0kev >> z1 >> m1 >> latticeConst >> hn >> cw >> ed >> iy >> nowout;
instream >> dx[1] >> rho[1];
instream >> zt[1][1] >> mt[1][1] >> t[1][1];
instream >> n[1];
instream >> dx[2] >> rho[2];
instream >> zt[2][1] >> mt[2][1] >> t[2][1];
instream >> n[2];
instream >> dx[3] >> rho[3];
instream >> zt[3][1] >> mt[3][1] >> t[3][1];
instream >> n[3];
for (w = 0; w <= 3; w++)
{ if (n[w] != 1) n[w] = 1; }
instream.close();
Layer = 3;
//done with primary (crude) setup, off to reading scoef.dat file
iz = z1;
getstructScoef(iz, scoefz1, “scoef1.dat”); //used to get pcoef data yy in trim85
//so we put the values in yy here immediately
for (w = 1; w <= 8; w++)
{ yy[w] = scoefz1.pcoef[w]; }
//note: although yy turns out to be just a dummy array
e0 = e0kev*1000; //convert to ev.
if (ed == 0.) ed = 25.0;
ef = Max(5.0, e0kev*0.1);
//alfa = angle of incidence, alpha = radian of alfa
alfa = 0.;
alpha = alfa*Pi/180;
tmin = 5.0;
tau = 0.0;
da = 3.0;
if (iy == 0) iy = 16381;
//now calculate the total depth of each layer = xx(l), and grid spacing cw
xx[1] = dx[1];
for (w = 2; w <= 3; w++) { xx[w] = dx[w] + xx[w-1]; }
if (cw == 0) cw = 0.01*xx[3];
L0 = cw;
//take care of any custom variable or struct I made
rstp.vfermi = 0.0; //set this to 0. for the time being (see log for explanation)
//now, off to avg mass of layer in the next void function
}
//avg mass and atomic number of each layer
void calculateAvgMassOfLayer()
{
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
h[LL] = h[LL] + t[LL][w];
//cout << “testing here..” << rstp.vfermi << endl;
}
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
t[LL][w] = t[LL][w]/h[LL];
m2[LL] = m2[LL] + t[LL][w] * mt[LL][w];
z2[LL] = z2[LL] + t[LL][w] * zt[LL][w];
//note: z2 wont be an integer once t has a value other than 1.0??
//so are we calculating average atomic number here? why?
}
}
//done with this, off to finding electronic stopping powers in the next function
}
void getStoppingForTarget()
{
iz1 = z1; ee = 0;
for (int LL = 1; LL <= Layer; LL++)
{
arho[LL] = rho[LL] * 0.6022/(m2[LL]);
mu[LL] = m1/(m2[LL]);
int ii = n[LL];
for (int nn = 1; nn <= ii; nn++)
{
//set rstp.se[1..1000] = 0. Clear it for the next loop
for (w = 1; w <= 1000; w++)
{ rstp.se[w] = 0.; }
izt = zt[LL][nn];
//calling getrstop now. units, lfctr, vfermi = 1 (doesnt matter)
getrStop(iz1, izt, e0kev, 1, 1., 1., rstp); //rstp defined in header
//set this anyway, though I dont calculate this in RSTOP
vf[LL][nn] = rstp.vfermi; //which is just set 0 in the struct def.
for (w = 1; w <= 1000; w++)
{
se[LL][w] = se[LL][w] + rstp.se[w] * t[LL][nn] * arho[LL];
}
}
}
//now, off to setting up initial conditions next function
}
void setInitialConditions()
{
nh = hn; //number of histories
for (int LL = 1; LL <= Layer; LL++)
{
a[LL] = 0.5292 * 0.8853 / ( pow(z1, 0.23) + pow(z2[LL], 0.23) );
//now calculate the mean flight path with the conditions given in trim85
f[LL] = a[LL] * m2[LL] / ( z1 * z2[LL] * 14.4 * (m1 + m2[LL] ) );
epso = e0 * f[LL];
epsdg[LL] = tmin * f[LL] * pow( (1.0 + mu[LL]) , 2) / (4.0 * mu[LL]);
fd[LL] = 0.01 * pow( z2[LL], (-7.0/3.0) );
kd[LL] = 0.1334 * pow ( z2[LL], (2.0/3.0) ) / sqrt( m2[LL] );
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
my[LL][w] = m1/mt[LL][w];
ec[LL][w] = 4.0 * my[LL][w] / pow( ( 1.0 + my[LL][w] ), 2);
ai[LL][w] = 0.5292 * 0.8853 / ( pow(z1,0.23) + pow(zt[LL][w],0.23) );
fi[LL][w] = ai[LL][w] * mt[LL][w] / ( z1 * zt[LL][w] * 14.4 * ( m1 + mt[LL][w] ) );
}
}
cout << “Setup finished. Starting Monte Carlo Loops..”;
//off to monte carlo loop in next routine
}
void MonteCarlo()
{
//custom variables and arrays for this section
double e;
double cosin = 0.0, siny = 0.0, sine = 0.0, cosy = 0.0;
double pl = 0.0;
int ic;
int LL = 1;
double eps;
double eeg;
double p;
double b;
int ie, ia; //not sure if ie or ia should be double. They are used to access elements
of the m[][] array at some point
double see;
double dee;
double s2, c2, ct, st;
double r, rr;
double ex1, ex2, ex3, ex4;
double v, v1;
double fr, fr1;
double q;
double roc, sqe;
double cc, aa, ff;
double delta, co;
double den;
double phi, psi;
double x1;
int ip;
//variables for crystal calculations
double sep = 0.0;
int ionCounter = 0;
double p1, p2;
double Theta = 0.0;
double rTheta = 0.0, rPhi = 0.0;
double thetaThreshold = 0.5;
double crystalMuonY = 0.0, crystalMuonZ = 0.0;
//amount of translations in y and z axes
double translationY = 0.0, translationZ = 0.0;
//Scatter Plot variables
const int numScatterPlotBins = 5;
double scatterPlot[numScatterPlotBins + 1] = {0.0};
//Vector declarations
//lattice constant of Target (input from file)
double latticeConstant = latticeConst;
Vector3 ions[4];
Vector3 ionsOrdered[4];
Vector3 neighborIonsBCC[14];
Vector3 neighborIonsFCC[14];
Vector3 ionTranslationY(0,translationY,0);
Vector3 ionTranslationZ(0,0,translationZ);
Vector3 unitzplus, unitzminus, unityplus, unityminus, unitxplus, unitxminus;
unitzplus.z = 1;
unitzminus.z = -1;
unityplus.y = 1;
unityminus.y = -1;
unitxplus.x = 1;
unitxminus.x = -1;
Vector3 initialDirection(1,0,0);
Vector3 d;
d.x = 1;
d *= latticeConstant/2;
Vector3 lx(latticeConstant/2, 0, 0);
Vector3 ly(0, latticeConstant/2, 0);
Vector3 lz(0, 0, latticeConstant/2);
Vector3 lambda;
Vector3 lambdaPrime;
Vector3 pVector;
Vector3 pUnitVector;
Vector3 sepVector;
Vector3 Di;
Vector3 DiPrev;
//Vector3 DiPrevToDi;
Vector3 delX;
Vector3 delX1, delX2;
Vector3 dummy1, dummy2, temp;
Vector3 scatterIonPos;
//initialize the random number generator
srand(time(NULL));
//open file to write output
ofstream outStream;
outStream.open(“coords0.txt”);
if(outStream.fail())
{
exitOnError(“Could not open Output file”);
}
//write basic information in the output file
//number of ions, ion energy, total depth, depth of each layer
outStream << nh << “\t” << e0kev << “\t” << xx[Layer] << “\t” << dx[1] << “\t”
<< dx[2] << “\t” << dx[3] << endl;
//open scatter plot file to write current Y and Z coordinates of muons at designated
intervals
ofstream scatterStream;
scatterStream.open(“scatterOut1.txt”);
if(scatterStream.fail())
{
exitOnError(“Could not open Scatter Plot Output file”);
}
//open range distribution file to write final X coordinates of muons
ofstream rangeStream;
rangeStream.open(“rangeOut1.txt”);
if(rangeStream.fail())
{
exitOnError(“Could not open Range Distribution Output file”);
}
//Open general information dump file
ofstream infoStream;
infoStream.open(“info1.txt”);
if(infoStream.fail())
{
exitOnError(“Could not open general information Output file”);
}
//Entering the target
//First set up for the top layer
for (ih = 1; ih <= nh; ih++)
{
avex = xsum / Max(1.0, (float)(ih - ib - it - 1));
if (talk == 2) cout << “Average ion range so far: “ << avex << “ angstroms.”
<<endl;
if (talk > 2) cout << “Now starting ion number “ << ih << endl;
e = e0;
//set scatterPlot array (the intervals)
scatterPlot[0] = 10;
scatterPlot[1] = 30;
scatterPlot[2] = 50;
scatterPlot[3] = 100;
scatterPlot[4] = 150;
scatterPlot[5] = 200;
/*
for(int ccc = 0; ccc <= numScatterPlotBins; ccc++)
{
cout << “scatter plot “ << ccc << “: “ << scatterPlot[ccc] << endl;
}
*/
//Initial Ion Positions
ions[0] = d + ionTranslationZ + unitzminus * (latticeConstant/2);
ions[1] = d + ionTranslationZ + unitzplus * (latticeConstant/2);
ions[2] = d * 2 + ionTranslationY + unityminus * (latticeConstant/2);
ions[3] = d * 2 + ionTranslationY + unityplus * (latticeConstant/2);
//Create a polygon that resides on the lateral axes.
//The points are put on anticlockwise order, which is important for
//testing whether the test point lies on this polygon
ionsOrdered[0] = ions[0];
ionsOrdered[1] = ions[2];
ionsOrdered[2] = ions[1];
ionsOrdered[3] = ions[3];
//generate random theta and phi angles.
rTheta = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * thetaThreshold;
rPhi = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * 2 * Pi;
//find corresponding x, y and z components of the direction vector.
//radius of the direction vector is 1
initialDirection.x = cos(rTheta);
initialDirection.z = sin(rTheta) * cos(rPhi);
initialDirection.y = sin(rTheta) * sin(rPhi);
//set the counter to 0 for a new ion
ionCounter = 0;
pl = 0.0;
ic = 0;
//set initial DiPrev - the origin
DiPrev.x = 0.0; DiPrev.y = 0.0; DiPrev.z = 0.0;
//set initial lambda, the direction of motion. Normalize it.
lambda.clear();
lambda = initialDirection;
lambda.normalize();
//set initial delX to origin
delX.clear();
//clear the dummy delX vectors, set them to origin
delX1.clear();
delX2.clear();
dummy1.clear();
dummy2.clear();
temp.clear();
LL = 1;
//set transmitted and backscattered to false
transmitted = 0;
backscattered = 0;
//set channeling to true
insideChannel = 1;
neighborFlag = 0;
//write the initial coordinates to the output file
outStream << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << endl << “Initial: “;
//cout << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << “r1 = “ << r1 << endl;
//cycle for each collision until the energy of the particle becomes too low, or
the particle backscatters, or it goes out of the last layer (transmission)
//needs a do while loop here,
//which I will mention as the ‘mother loop’ from now.
do
{
ic = ic + 1;
eps = e * f[LL];
eeg = sqrt(eps*epsdg[LL]);
//pmax[LL] = a[LL] / (eeg + sqrt(eeg) + 0.125 * pow( eeg, 0.1) );
pmax[LL] = sqrt(3) * (latticeConstant / 2) * 0.7;
//Calculate impact parameter and choose the atom to scatter from.
//Do this for ion pairs 0,1 and 2,3.
if (ionCounter == 0)
{
delX1 = ions[0] - DiPrev;
delX2 = ions[1] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[0];
ions[0] = ions[1];
ions[1] = temp;
//cout << “Vertical Ions swapped” << endl;
}
}
if (ionCounter == 2)
{
delX1 = ions[2] - DiPrev;
delX2 = ions[3] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[2];
ions[2] = ions[3];
ions[3] = temp;
//cout << “Horizontal Ions swapped” << endl;
}
}
//now calculate impact parameter
if(neighborFlag == 0)
{
delX = ions[ionCounter] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
else if(neighborFlag == 1)
{
double impact[13] = {0.0};
double radial[13] = {0.0};
double S[13] = {0.0};
double sumS = 0.0;
double Probability[13] = {0.0};
double rnd_candidate = 0.0;
int selected_candidate = -1;
for(int ncount = 0; ncount <= 13; ncount++)
{
delX = neighborIonsBCC[ncount] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
//scatterIonPos = neighborIonsBCC[ncount];
impact[ncount] = p;
radial[ncount] = delX.magnitude();
S[ncount] = 1 / ( pow(impact[ncount],2) * radial[ncount] );
sumS += S[ncount];
//general scheme of selecting the neighbor ion
// if(p < pmax[LL])
// {
// scatterIonPos = neighborIonsBCC[ncount];
// //cout << “Neighbor “ << ncount << “ is selected” << endl;
// break;
// }
}
for(int ncount = 0; ncount <= 13; ncount++)
{
Probability[ncount] = S[ncount] / sumS;
}
//print out the probability array
cout << endl;
for(int ncount = 0; ncount <= 13; ncount++)
{
//cout << Probability[ncount] << “ “;
infoStream << Probability[ncount] << “ “;
}
infoStream << endl;
//cout << endl;
//random number between 0 and 1
rnd_candidate = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) );
//cout << “rand_candidate: “ << rnd_candidate << endl;
//choose the candidate for scattering
selected_candidate = whichNonUniformBin(rnd_candidate, Probability, 13);
//cout << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate <<
endl;
infoStream << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate
<< endl;
//assign the scatterIonPos variable to the selected neighbor
scatterIonPos = neighborIonsBCC[selected_candidate];
//cout << “Scattering Ion Position: “; scatterIonPos.printVector();
//find the essential quantities for the selected neighbor
delX = neighborIonsBCC[selected_candidate] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
//find eps and b using fi[LL][nn], using nn that I was supposed to find from above
//here im deliberately using nn = 1
eps = fi[LL][1] * e;
b = p / ai[LL][1];
if (eps > 10) //rutherford scattering
{
s2 = 1.0 / (1.0 + (1.0 + b * (1.0 + b)) * pow((2.0 * eps * b), 2) );
c2 = 1.0 - s2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
else //magic formula
{
r = b;
rr = -2.7 * log(eps * b);
if (rr >= b)//note >= sign instead < in trim85
{
rr = -2.7 * log(eps * rr);
if (rr >= b)//note >= sign instead < in trim85
{
r = rr;
}
}
//do while loop that replaces line 330 loop
do
{
ex1 = 0.18175 * exp(-3.1998 * r);
ex2 = 0.50986 * exp(-0.94229 * r);
ex3 = 0.28022 * exp(-0.4029 * r);
ex4 = 0.028171 * exp(-0.20162 * r);
v = (ex1 + ex2 + ex3 + ex4) / r;
v1 = -(v + 3.1998 * ex1 + 0.94229 * ex2 + 0.4029 * ex3 + 0.20162 * ex4) / r;
fr = b * b / r + v * r / eps - r;
fr1 = -b * b / (r * r) + (v + v1 * r) / eps - 1.0;
q = fr / fr1;
r = r - q;
}
while( (Abs(q / r)) > 0.001 );
roc = -2.0 * (eps - v) / v1;
sqe = sqrt(eps);
//5 parameter magic scattering calculation
//below is for universal potential
cc = (0.011615 + sqe) / (0.0071222 + sqe);
aa = 2.0 * eps * (1.0 + (0.99229 / sqe) ) * ( pow(b, cc) );
ff = ( sqrt(aa * aa + 1.0) - aa) * ( (9.3066 + eps) / (14.813 + eps) );
delta = (r - b) * aa * ff / (ff + 1.0);
co = (b + delta + roc) / (r + roc);
c2 = co * co;
s2 = 1.0 - c2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
Theta = acos(ct);
//we are done finding theta (in CM system). So calculate all other quantities.
//find separation and the separation vector.
phi = (Pi - Theta) / 2;
sep = p / tan(phi);
sepVector = lambda * sep;
//find theta in laboratory frame - psi
psi = atan(st / (ct + my[LL][1] ) );
//note: change my[LL][1] to my[LL][nn] when the above section is fixed.
if (psi < 0 ) psi = psi + Pi; //should I do this for crystals?
//find Di, the scattering point vector
Di = DiPrev + delX + pVector - sepVector;
//find new direction of motion
lambdaPrime = lambda * cos(psi) + pUnitVector * sin(psi);
lambdaPrime.normalize();
//find length of step, ls = distance of Di from DiPrev
ls = Di.getDistance(DiPrev);
//find energy lost due to electronic stopping, dee
ie = (int)(e/e0kev+0.5); //should it be 0.5? or less so that ie <=1000?
see = se[LL][ie];
if (e < e0kev) see = se[LL][1] * sqrt(e/e0kev);
dee = ls * see;
// den = energy transferred to recoil
den = ec[LL][1] * s2 * e; //note: I am using ec[LL][1] here instead of [LL][nn].
//cout << “den = “ << den << “, dee = “ << dee << endl;
infoStream << “den = “ << den << “, dee = “ << dee << endl;
e = e - den - dee;
//cout << endl<< “current ion energy: “ << e << endl;
if (dee > maximum) maximum = dee;
pl = pl + ls - tau;
//write the ion position to output file
outStream << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
if((ic%30)==0)
{
//cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
}
//determine which scatter plot Di’s x value belongs to.
//output the y and z coordinates to scatter plot file accordingly.
for(int cc = 0; cc <= numScatterPlotBins; cc++)
{
if( Di.x >= (scatterPlot[cc]) )
{
crystalMuonY = Di.y - translationY;
crystalMuonZ = Di.z - translationZ;
//cout << “scatter plot “ << ct << “: “ << scatterPlot[ct] << endl;
scatterStream << scatterPlot[cc] << “\t” << crystalMuonY << “\t” <<
crystalMuonZ << endl;
//set scatterPlot[ss] to a big number
scatterPlot[cc] = 10000;
//break out of this for loop
break;
}
}
//determine if Di is in the channeling region.
//insideChannel = Di.isInsidePolygon(ionsOrdered, 4);
//break out of parent loop if not inside the channel
if(insideChannel == 0)
{
cout << “Ion “ << ih << “ is out of Channel” << endl;
cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
break;
}
//determine which layer the next collision will be in
if (Di.x < 0.0) //particle is backscattered
{
backscattered = 1; //cout << “ion number “ << ih << “ backscattered.” << endl;
infoStream << “ion number “ << ih << “ backscattered.” << endl;
ib = ib + 1;
eb = eb + e;
break; //break out of ‘mother do loop’ and continue with the next session of
for loop.
}
//here we set the current or next layer the particle will be in
for (w = 1; w <= Layer; w++)
{
if ( (Di.x <= xx[w]) && (w == 1) )
{
LL = 1;
//cout << endl<<”ion is in layer “ << LL << endl;
break;
//break out of this For loop and go check if the particle is transmitted.
}
else if ( (Di.x <= xx[w]) && (Di.x > xx[w-1]) )
{
LL = w;
//cout << “ion is in layer “ << LL <<endl;
break; //break out of this For loop and go check if the particle is
transmitted.
}
}
//now, check for particle transmission, i.e. whether the particle went out of the
last layer.
if(Di.x >= xx[Layer])
{
//particle is transmitted, take care of appropriate variables and break
transmitted = 1;//cout << “ion number “ << ih << “ transmitted.” << endl;
it = it + 1;
et = et + e;
ia = 57.295779 * acos(cosin) / da + 1.0;
ie = 100 * e / e0 + 1.0;
//m[ie][ia] = m[ie][ia] + 1;//note: how is this possible? ie and ia should be
integers in order to access the elements of the array m[][]. But we calculate them as
doubles here!
break; //break out of the ‘mother’ do loop
}
//now take care of ionCounter and other variables for the next scattering
if(neighborFlag == 0)
{
if(ionCounter == 3)
{
//ionCounter = 0;
neighborFlag = 1;
scatterIonPos = ions[3];
//cout << endl << “got out of first two layers” << endl;
}
else
{
ionCounter++;
}
}
if(neighborFlag == 1)
{
//cout << “Updating Neighbor Ions” << endl;
neighborIonsBCC[0] = scatterIonPos + lx - ly + lz;
neighborIonsBCC[1] = scatterIonPos + lx + ly + lz;
neighborIonsBCC[2] = scatterIonPos + lx + ly - lz;
neighborIonsBCC[3] = scatterIonPos + lx - ly - lz;
neighborIonsBCC[4] = scatterIonPos + lx * 2;
neighborIonsBCC[5] = scatterIonPos - lx - ly - lz;
neighborIonsBCC[6] = scatterIonPos - lx + ly - lz;
neighborIonsBCC[7] = scatterIonPos - lx + ly + lz;
neighborIonsBCC[8] = scatterIonPos - lx - ly + lz;
neighborIonsBCC[9] = scatterIonPos + lz * 2;
neighborIonsBCC[10] = scatterIonPos - lz * 2;
neighborIonsBCC[11] = scatterIonPos + ly * 2;
neighborIonsBCC[12] = scatterIonPos - ly * 2;
neighborIonsBCC[13] = scatterIonPos - lx * 2;
}
//set DiPrev to Di
DiPrev = Di;
//update current lambda to lambdaPrime
lambda = lambdaPrime;
//now the while condition of the mother do loop checks if the particle has lesser
energy than our lowest energy limit, ef.
}
while(e > ef);
//since we are out of the mother do loop now, the particle must have come to a
stop. So, increase the final particle distributions if the particle has not been
transmitted or backscattered.
if( ((transmitted == 0)) && ((backscattered == 0)) && ((insideChannel == 1)) )
{
ip = (int)(pl/cw + 1.0);
if(ip > 100) ip = 100;
//ipl[ip] = ipl[ip] + 1;
xsum = xsum + Di.x;
//my own bin function
selectedXBin = whichBin(Di.x, xx[Layer], numXBin);
//write the selected bin to the output file
//outStream << selectedXBin << endl;
//cout << x << endl << xx[Layer] << endl << numXBin << endl << selectedXBin;
xBin[selectedXBin] = xBin[selectedXBin] + 1;
//print final x value for plotting histogram
//cout << “ion “ << ih << “ final x: “ << Di.x << endl;
infoStream << “ion “ << ih << “ final x: “ << Di.x << endl;
//cout << Di.x << “,”;
rangeStream << Di.x << endl;
plsum = plsum + pl;
icsum = icsum + ic;
//ipl is the ion path length - the total avg. distance the ion travels
regardless of direction before it comes to stop
}
//that brings us to the end of one ion’s journey, now go to next ion by going back
to the for loop’s beginning..
}
//and this ends the monte carlo loop function. Take care of necessary structures and
variables that need to be cleared/deleted
outStream.close();
scatterStream.close();
infoStream << “Number of Backscattered Ions: “ << ib << endl;
infoStream.close();
rangeStream.close();
}
int whichNonUniformBin(double e, double arr[], int numBins)
{
double low = 0, high = arr[0];
if((e>=low) && (e<high))
return 0;
else
{
for(int i = 0; i < numBins; i++)
{
low += arr[i];
high += arr[i+1];
//cout << “\tlow: “ << low << “, high:” << high << endl;
if((e>=low) && (e<high))
return i;
}
}
}
139
//============================================================================
// Name : monte.cpp
// Author : Nazmus Saquib
// Version :
// Copyright :
// Description : BCA code in C++
//============================================================================
#include “Globals.h”
#include “scoef.h”
#include “rstop.h”
#include “muscle_bca.h”
#include “vectorGeometry.h”
const int numXBin = 100;
const int numIons = 1;
int xBin[numXBin+1] = {0};
int selectedXBin = 0;
double rho[4]={0.0};
int n[]={0,0,0,0};
double e0kev, m1, cw, ed, latticeConst;
int z1, hn, iy, nowout;
double dx[3] = {0.0};
int zt[3][7] = {0};
double mt[3][7] = {0.};
double t[3][7] = {0.};
int Layer; //use this for number of layers rather than the L in the program;
//remember this cannot be set to 0. Other loops/arrays may start from
//0, but keep this >= 1;
//the arrays..
double my[3][7]= {0},
ai[3][7]= {0},
fi[3][7]= {0},
ec[3][7]= {0},
io[3][7]= {0},
k[3]= {0},
kl[3][7]= {0};
double vf[3][7]= {0},
mu[3]= {0},
ioniz[3]= {0},
h[3]= {0},
xx[3]= {0},
m2[3]= {0.0},
z2[3]= {0},
c[3]= {0},
epsbk[3]= {0},
arho[3]= {0};
double a[3]= {0},
f[3]= {0},
lm[3]= {0},
pmax[3]= {0},
fd[3]= {0},
kd[3]= {0},
sbk[3]= {0},
lf[3]= {0},
yy[8]= {0};
double se[3][1000]= {0.0},
seo[1000]= {0.0},
epsdg[3]= {0.0};
double ls = 0., lo = 0., maximum = 0.;
double xsum = 0, x2sum = 0, x3sum = 0, x4sum = 0, plsum = 0, pl2sum = 0;
double avex = 0, vari = 0, sigma = 0, v = 0, v2 = 0, Gamma = 0, beta = 0, y = 0, avepl
= 0, sigpl = 0, avecol = 0;
int i = 0, j = 0;
int ib = 0, it = 0;
double eb = 0.0, et = 0.0;
int icsum = 0;
double y2sum = 0, xy2sum = 0, x2y2su = 0, y4sum = 0;
double tau = 0;
int iii = -1;
//my dummy vars
int w; double q;
//my customized data structures or vars
scoefData scoefz1;
rstopData rstp;
//these vars (continuing from this line) are added later as needed, vars that were not
declared in the initialization of trim85 but showed up in the middle.
double e0, ef;
int iz;
double alfa, alpha;
double tmin, da;
double L0;
int iz1;
double ee;
int izt;
double nh;
double epso;
int ih;
double e;
//boolean for keeping track of a particle being transmitted or backscattered
int transmitted = 0;
int backscattered = 0;
//boolean for keeping track of channeling
int insideChannel = 1;
//boolean for determining whether to scatter from neighbor atoms
int neighborFlag = 0;
//main function
int main()
{
cout << “Initializing” << endl;
Initialize(“IronInput.dat”);
calculateAvgMassOfLayer();
getStoppingForTarget();
setInitialConditions();
MonteCarlo();
/* *********************** Testing Ground for arrays and variables
******************** */
for (w = 1; w <= 8; w++) cout << “\t “ << yy[w];
for (w = 1; w <= 3; w++) cout << “\n\t “ << xx[w];
cout << “CW or L0: “ << L0;
//(trouble! The values of n[] elements are changing like crazy)
cout << endl << n[0] << “\t” << n[1] << “\t” << n[2] << “\t” << n[3] << endl;
cout << endl << rho[0] << “\t” << rho[1] << “\t” << rho[2] << “\t” << rho[3] <<
“\t” << rho[4] << endl;
//test z2[], m2[] arrays
for (w = 1; w <= Layer; w++) cout << “\t “ << z2[w];
for (w = 1; w <= Layer; w++) cout << “\n\t “ << m2[w];
//test the se values
cout << endl << se[1][1000] << “ “ << se[2][1000] << “ “ << se[3][1000] << endl;
//test the se[] values by printing 10th element from the array (to be implemented)
//for (w = 1; w <= 100; w++)
//{
//for (int sss = 1; sss <= 50; sss++)
//{
//cout << “\t” << mpart[w][sss];
//}
//}
/* *********************** End of Testing Ground ************************** */
cout << endl;
//Now print values of each bin in xBin
//for (w = 1; w <= numXBin; w++) cout << xBin[w] << “,”;
//print final x values
cout << endl;
cout << “Number of Backscattered Ions: “ << ib << endl;
cout << “Number of Transmitted Ions: “ << it << endl;
return 0;
}
//end of main
//Helper functions follow from here
//initialize variables and setup each layer over here
void Initialize(char* filename)
{
//Read command file
ifstream instream;
instream.open(filename,ios::in);
cout << filename;
if (!instream)
{
exitOnError(filename);
}
instream >> e0kev >> z1 >> m1 >> latticeConst >> hn >> cw >> ed >> iy >> nowout;
instream >> dx[1] >> rho[1];
instream >> zt[1][1] >> mt[1][1] >> t[1][1];
instream >> n[1];
instream >> dx[2] >> rho[2];
instream >> zt[2][1] >> mt[2][1] >> t[2][1];
instream >> n[2];
instream >> dx[3] >> rho[3];
instream >> zt[3][1] >> mt[3][1] >> t[3][1];
instream >> n[3];
for (w = 0; w <= 3; w++)
{ if (n[w] != 1) n[w] = 1; }
instream.close();
Layer = 3;
//done with primary (crude) setup, off to reading scoef.dat file
iz = z1;
getstructScoef(iz, scoefz1, “scoef1.dat”); //used to get pcoef data yy in trim85
//so we put the values in yy here immediately
for (w = 1; w <= 8; w++)
{ yy[w] = scoefz1.pcoef[w]; }
//note: although yy turns out to be just a dummy array
e0 = e0kev*1000; //convert to ev.
if (ed == 0.) ed = 25.0;
ef = Max(5.0, e0kev*0.1);
//alfa = angle of incidence, alpha = radian of alfa
alfa = 0.;
alpha = alfa*Pi/180;
tmin = 5.0;
tau = 0.0;
da = 3.0;
if (iy == 0) iy = 16381;
//now calculate the total depth of each layer = xx(l), and grid spacing cw
xx[1] = dx[1];
for (w = 2; w <= 3; w++) { xx[w] = dx[w] + xx[w-1]; }
if (cw == 0) cw = 0.01*xx[3];
L0 = cw;
//take care of any custom variable or struct I made
rstp.vfermi = 0.0; //set this to 0. for the time being (see log for explanation)
//now, off to avg mass of layer in the next void function
}
//avg mass and atomic number of each layer
void calculateAvgMassOfLayer()
{
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
h[LL] = h[LL] + t[LL][w];
//cout << “testing here..” << rstp.vfermi << endl;
}
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
t[LL][w] = t[LL][w]/h[LL];
m2[LL] = m2[LL] + t[LL][w] * mt[LL][w];
z2[LL] = z2[LL] + t[LL][w] * zt[LL][w];
//note: z2 wont be an integer once t has a value other than 1.0??
//so are we calculating average atomic number here? why?
}
}
//done with this, off to finding electronic stopping powers in the next function
}
void getStoppingForTarget()
{
iz1 = z1; ee = 0;
for (int LL = 1; LL <= Layer; LL++)
{
arho[LL] = rho[LL] * 0.6022/(m2[LL]);
mu[LL] = m1/(m2[LL]);
int ii = n[LL];
for (int nn = 1; nn <= ii; nn++)
{
//set rstp.se[1..1000] = 0. Clear it for the next loop
for (w = 1; w <= 1000; w++)
{ rstp.se[w] = 0.; }
izt = zt[LL][nn];
//calling getrstop now. units, lfctr, vfermi = 1 (doesnt matter)
getrStop(iz1, izt, e0kev, 1, 1., 1., rstp); //rstp defined in header
//set this anyway, though I dont calculate this in RSTOP
vf[LL][nn] = rstp.vfermi; //which is just set 0 in the struct def.
for (w = 1; w <= 1000; w++)
{
se[LL][w] = se[LL][w] + rstp.se[w] * t[LL][nn] * arho[LL];
}
}
}
//now, off to setting up initial conditions next function
}
void setInitialConditions()
{
nh = hn; //number of histories
for (int LL = 1; LL <= Layer; LL++)
{
a[LL] = 0.5292 * 0.8853 / ( pow(z1, 0.23) + pow(z2[LL], 0.23) );
//now calculate the mean flight path with the conditions given in trim85
f[LL] = a[LL] * m2[LL] / ( z1 * z2[LL] * 14.4 * (m1 + m2[LL] ) );
epso = e0 * f[LL];
epsdg[LL] = tmin * f[LL] * pow( (1.0 + mu[LL]) , 2) / (4.0 * mu[LL]);
fd[LL] = 0.01 * pow( z2[LL], (-7.0/3.0) );
kd[LL] = 0.1334 * pow ( z2[LL], (2.0/3.0) ) / sqrt( m2[LL] );
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
my[LL][w] = m1/mt[LL][w];
ec[LL][w] = 4.0 * my[LL][w] / pow( ( 1.0 + my[LL][w] ), 2);
ai[LL][w] = 0.5292 * 0.8853 / ( pow(z1,0.23) + pow(zt[LL][w],0.23) );
fi[LL][w] = ai[LL][w] * mt[LL][w] / ( z1 * zt[LL][w] * 14.4 * ( m1 + mt[LL][w] ) );
}
}
cout << “Setup finished. Starting Monte Carlo Loops..”;
//off to monte carlo loop in next routine
}
void MonteCarlo()
{
//custom variables and arrays for this section
double e;
double cosin = 0.0, siny = 0.0, sine = 0.0, cosy = 0.0;
double pl = 0.0;
int ic;
int LL = 1;
double eps;
double eeg;
double p;
double b;
int ie, ia; //not sure if ie or ia should be double. They are used to access elements
of the m[][] array at some point
double see;
double dee;
double s2, c2, ct, st;
double r, rr;
double ex1, ex2, ex3, ex4;
double v, v1;
double fr, fr1;
double q;
double roc, sqe;
double cc, aa, ff;
double delta, co;
double den;
double phi, psi;
double x1;
int ip;
//variables for crystal calculations
double sep = 0.0;
int ionCounter = 0;
double p1, p2;
double Theta = 0.0;
double rTheta = 0.0, rPhi = 0.0;
double thetaThreshold = 0.5;
double crystalMuonY = 0.0, crystalMuonZ = 0.0;
//amount of translations in y and z axes
double translationY = 0.0, translationZ = 0.0;
//Scatter Plot variables
const int numScatterPlotBins = 5;
double scatterPlot[numScatterPlotBins + 1] = {0.0};
//Vector declarations
//lattice constant of Target (input from file)
double latticeConstant = latticeConst;
Vector3 ions[4];
Vector3 ionsOrdered[4];
Vector3 neighborIonsBCC[14];
Vector3 neighborIonsFCC[14];
Vector3 ionTranslationY(0,translationY,0);
Vector3 ionTranslationZ(0,0,translationZ);
Vector3 unitzplus, unitzminus, unityplus, unityminus, unitxplus, unitxminus;
unitzplus.z = 1;
unitzminus.z = -1;
unityplus.y = 1;
unityminus.y = -1;
unitxplus.x = 1;
unitxminus.x = -1;
Vector3 initialDirection(1,0,0);
Vector3 d;
d.x = 1;
d *= latticeConstant/2;
Vector3 lx(latticeConstant/2, 0, 0);
Vector3 ly(0, latticeConstant/2, 0);
Vector3 lz(0, 0, latticeConstant/2);
Vector3 lambda;
Vector3 lambdaPrime;
Vector3 pVector;
Vector3 pUnitVector;
Vector3 sepVector;
Vector3 Di;
Vector3 DiPrev;
//Vector3 DiPrevToDi;
Vector3 delX;
Vector3 delX1, delX2;
Vector3 dummy1, dummy2, temp;
Vector3 scatterIonPos;
//initialize the random number generator
srand(time(NULL));
//open file to write output
ofstream outStream;
outStream.open(“coords0.txt”);
if(outStream.fail())
{
exitOnError(“Could not open Output file”);
}
//write basic information in the output file
//number of ions, ion energy, total depth, depth of each layer
outStream << nh << “\t” << e0kev << “\t” << xx[Layer] << “\t” << dx[1] << “\t”
<< dx[2] << “\t” << dx[3] << endl;
//open scatter plot file to write current Y and Z coordinates of muons at designated
intervals
ofstream scatterStream;
scatterStream.open(“scatterOut1.txt”);
if(scatterStream.fail())
{
exitOnError(“Could not open Scatter Plot Output file”);
}
//open range distribution file to write final X coordinates of muons
ofstream rangeStream;
rangeStream.open(“rangeOut1.txt”);
if(rangeStream.fail())
{
exitOnError(“Could not open Range Distribution Output file”);
}
//Open general information dump file
ofstream infoStream;
infoStream.open(“info1.txt”);
if(infoStream.fail())
{
exitOnError(“Could not open general information Output file”);
}
//Entering the target
//First set up for the top layer
for (ih = 1; ih <= nh; ih++)
{
avex = xsum / Max(1.0, (float)(ih - ib - it - 1));
if (talk == 2) cout << “Average ion range so far: “ << avex << “ angstroms.”
<<endl;
if (talk > 2) cout << “Now starting ion number “ << ih << endl;
e = e0;
//set scatterPlot array (the intervals)
scatterPlot[0] = 10;
scatterPlot[1] = 30;
scatterPlot[2] = 50;
scatterPlot[3] = 100;
scatterPlot[4] = 150;
scatterPlot[5] = 200;
/*
for(int ccc = 0; ccc <= numScatterPlotBins; ccc++)
{
cout << “scatter plot “ << ccc << “: “ << scatterPlot[ccc] << endl;
}
*/
//Initial Ion Positions
ions[0] = d + ionTranslationZ + unitzminus * (latticeConstant/2);
ions[1] = d + ionTranslationZ + unitzplus * (latticeConstant/2);
ions[2] = d * 2 + ionTranslationY + unityminus * (latticeConstant/2);
ions[3] = d * 2 + ionTranslationY + unityplus * (latticeConstant/2);
//Create a polygon that resides on the lateral axes.
//The points are put on anticlockwise order, which is important for
//testing whether the test point lies on this polygon
ionsOrdered[0] = ions[0];
ionsOrdered[1] = ions[2];
ionsOrdered[2] = ions[1];
ionsOrdered[3] = ions[3];
//generate random theta and phi angles.
rTheta = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * thetaThreshold;
rPhi = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * 2 * Pi;
//find corresponding x, y and z components of the direction vector.
//radius of the direction vector is 1
initialDirection.x = cos(rTheta);
initialDirection.z = sin(rTheta) * cos(rPhi);
initialDirection.y = sin(rTheta) * sin(rPhi);
//set the counter to 0 for a new ion
ionCounter = 0;
pl = 0.0;
ic = 0;
//set initial DiPrev - the origin
DiPrev.x = 0.0; DiPrev.y = 0.0; DiPrev.z = 0.0;
//set initial lambda, the direction of motion. Normalize it.
lambda.clear();
lambda = initialDirection;
lambda.normalize();
//set initial delX to origin
delX.clear();
//clear the dummy delX vectors, set them to origin
delX1.clear();
delX2.clear();
dummy1.clear();
dummy2.clear();
temp.clear();
LL = 1;
//set transmitted and backscattered to false
transmitted = 0;
backscattered = 0;
//set channeling to true
insideChannel = 1;
neighborFlag = 0;
//write the initial coordinates to the output file
outStream << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << endl << “Initial: “;
//cout << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << “r1 = “ << r1 << endl;
//cycle for each collision until the energy of the particle becomes too low, or
the particle backscatters, or it goes out of the last layer (transmission)
//needs a do while loop here,
//which I will mention as the ‘mother loop’ from now.
do
{
ic = ic + 1;
eps = e * f[LL];
eeg = sqrt(eps*epsdg[LL]);
//pmax[LL] = a[LL] / (eeg + sqrt(eeg) + 0.125 * pow( eeg, 0.1) );
pmax[LL] = sqrt(3) * (latticeConstant / 2) * 0.7;
//Calculate impact parameter and choose the atom to scatter from.
//Do this for ion pairs 0,1 and 2,3.
if (ionCounter == 0)
{
delX1 = ions[0] - DiPrev;
delX2 = ions[1] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[0];
ions[0] = ions[1];
ions[1] = temp;
//cout << “Vertical Ions swapped” << endl;
}
}
if (ionCounter == 2)
{
delX1 = ions[2] - DiPrev;
delX2 = ions[3] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[2];
ions[2] = ions[3];
ions[3] = temp;
//cout << “Horizontal Ions swapped” << endl;
}
}
//now calculate impact parameter
if(neighborFlag == 0)
{
delX = ions[ionCounter] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
else if(neighborFlag == 1)
{
double impact[13] = {0.0};
double radial[13] = {0.0};
double S[13] = {0.0};
double sumS = 0.0;
double Probability[13] = {0.0};
double rnd_candidate = 0.0;
int selected_candidate = -1;
for(int ncount = 0; ncount <= 13; ncount++)
{
delX = neighborIonsBCC[ncount] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
//scatterIonPos = neighborIonsBCC[ncount];
impact[ncount] = p;
radial[ncount] = delX.magnitude();
S[ncount] = 1 / ( pow(impact[ncount],2) * radial[ncount] );
sumS += S[ncount];
//general scheme of selecting the neighbor ion
// if(p < pmax[LL])
// {
// scatterIonPos = neighborIonsBCC[ncount];
// //cout << “Neighbor “ << ncount << “ is selected” << endl;
// break;
// }
}
for(int ncount = 0; ncount <= 13; ncount++)
{
Probability[ncount] = S[ncount] / sumS;
}
//print out the probability array
cout << endl;
for(int ncount = 0; ncount <= 13; ncount++)
{
//cout << Probability[ncount] << “ “;
infoStream << Probability[ncount] << “ “;
}
infoStream << endl;
//cout << endl;
//random number between 0 and 1
rnd_candidate = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) );
//cout << “rand_candidate: “ << rnd_candidate << endl;
//choose the candidate for scattering
selected_candidate = whichNonUniformBin(rnd_candidate, Probability, 13);
//cout << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate <<
endl;
infoStream << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate
<< endl;
//assign the scatterIonPos variable to the selected neighbor
scatterIonPos = neighborIonsBCC[selected_candidate];
//cout << “Scattering Ion Position: “; scatterIonPos.printVector();
//find the essential quantities for the selected neighbor
delX = neighborIonsBCC[selected_candidate] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
//find eps and b using fi[LL][nn], using nn that I was supposed to find from above
//here im deliberately using nn = 1
eps = fi[LL][1] * e;
b = p / ai[LL][1];
if (eps > 10) //rutherford scattering
{
s2 = 1.0 / (1.0 + (1.0 + b * (1.0 + b)) * pow((2.0 * eps * b), 2) );
c2 = 1.0 - s2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
else //magic formula
{
r = b;
rr = -2.7 * log(eps * b);
if (rr >= b)//note >= sign instead < in trim85
{
rr = -2.7 * log(eps * rr);
if (rr >= b)//note >= sign instead < in trim85
{
r = rr;
}
}
//do while loop that replaces line 330 loop
do
{
ex1 = 0.18175 * exp(-3.1998 * r);
ex2 = 0.50986 * exp(-0.94229 * r);
ex3 = 0.28022 * exp(-0.4029 * r);
ex4 = 0.028171 * exp(-0.20162 * r);
v = (ex1 + ex2 + ex3 + ex4) / r;
v1 = -(v + 3.1998 * ex1 + 0.94229 * ex2 + 0.4029 * ex3 + 0.20162 * ex4) / r;
fr = b * b / r + v * r / eps - r;
fr1 = -b * b / (r * r) + (v + v1 * r) / eps - 1.0;
q = fr / fr1;
r = r - q;
}
while( (Abs(q / r)) > 0.001 );
roc = -2.0 * (eps - v) / v1;
sqe = sqrt(eps);
//5 parameter magic scattering calculation
//below is for universal potential
cc = (0.011615 + sqe) / (0.0071222 + sqe);
aa = 2.0 * eps * (1.0 + (0.99229 / sqe) ) * ( pow(b, cc) );
ff = ( sqrt(aa * aa + 1.0) - aa) * ( (9.3066 + eps) / (14.813 + eps) );
delta = (r - b) * aa * ff / (ff + 1.0);
co = (b + delta + roc) / (r + roc);
c2 = co * co;
s2 = 1.0 - c2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
Theta = acos(ct);
//we are done finding theta (in CM system). So calculate all other quantities.
//find separation and the separation vector.
phi = (Pi - Theta) / 2;
sep = p / tan(phi);
sepVector = lambda * sep;
//find theta in laboratory frame - psi
psi = atan(st / (ct + my[LL][1] ) );
//note: change my[LL][1] to my[LL][nn] when the above section is fixed.
if (psi < 0 ) psi = psi + Pi; //should I do this for crystals?
//find Di, the scattering point vector
Di = DiPrev + delX + pVector - sepVector;
//find new direction of motion
lambdaPrime = lambda * cos(psi) + pUnitVector * sin(psi);
lambdaPrime.normalize();
//find length of step, ls = distance of Di from DiPrev
ls = Di.getDistance(DiPrev);
//find energy lost due to electronic stopping, dee
ie = (int)(e/e0kev+0.5); //should it be 0.5? or less so that ie <=1000?
see = se[LL][ie];
if (e < e0kev) see = se[LL][1] * sqrt(e/e0kev);
dee = ls * see;
// den = energy transferred to recoil
den = ec[LL][1] * s2 * e; //note: I am using ec[LL][1] here instead of [LL][nn].
//cout << “den = “ << den << “, dee = “ << dee << endl;
infoStream << “den = “ << den << “, dee = “ << dee << endl;
e = e - den - dee;
//cout << endl<< “current ion energy: “ << e << endl;
if (dee > maximum) maximum = dee;
pl = pl + ls - tau;
//write the ion position to output file
outStream << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
if((ic%30)==0)
{
//cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
}
//determine which scatter plot Di’s x value belongs to.
//output the y and z coordinates to scatter plot file accordingly.
for(int cc = 0; cc <= numScatterPlotBins; cc++)
{
if( Di.x >= (scatterPlot[cc]) )
{
crystalMuonY = Di.y - translationY;
crystalMuonZ = Di.z - translationZ;
//cout << “scatter plot “ << ct << “: “ << scatterPlot[ct] << endl;
scatterStream << scatterPlot[cc] << “\t” << crystalMuonY << “\t” <<
crystalMuonZ << endl;
//set scatterPlot[ss] to a big number
scatterPlot[cc] = 10000;
//break out of this for loop
break;
}
}
//determine if Di is in the channeling region.
//insideChannel = Di.isInsidePolygon(ionsOrdered, 4);
//break out of parent loop if not inside the channel
if(insideChannel == 0)
{
cout << “Ion “ << ih << “ is out of Channel” << endl;
cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
break;
}
//determine which layer the next collision will be in
if (Di.x < 0.0) //particle is backscattered
{
backscattered = 1; //cout << “ion number “ << ih << “ backscattered.” << endl;
infoStream << “ion number “ << ih << “ backscattered.” << endl;
ib = ib + 1;
eb = eb + e;
break; //break out of ‘mother do loop’ and continue with the next session of
for loop.
}
//here we set the current or next layer the particle will be in
for (w = 1; w <= Layer; w++)
{
if ( (Di.x <= xx[w]) && (w == 1) )
{
LL = 1;
//cout << endl<<”ion is in layer “ << LL << endl;
break;
//break out of this For loop and go check if the particle is transmitted.
}
else if ( (Di.x <= xx[w]) && (Di.x > xx[w-1]) )
{
LL = w;
//cout << “ion is in layer “ << LL <<endl;
break; //break out of this For loop and go check if the particle is
transmitted.
}
}
//now, check for particle transmission, i.e. whether the particle went out of the
last layer.
if(Di.x >= xx[Layer])
{
//particle is transmitted, take care of appropriate variables and break
transmitted = 1;//cout << “ion number “ << ih << “ transmitted.” << endl;
it = it + 1;
et = et + e;
ia = 57.295779 * acos(cosin) / da + 1.0;
ie = 100 * e / e0 + 1.0;
//m[ie][ia] = m[ie][ia] + 1;//note: how is this possible? ie and ia should be
integers in order to access the elements of the array m[][]. But we calculate them as
doubles here!
break; //break out of the ‘mother’ do loop
}
//now take care of ionCounter and other variables for the next scattering
if(neighborFlag == 0)
{
if(ionCounter == 3)
{
//ionCounter = 0;
neighborFlag = 1;
scatterIonPos = ions[3];
//cout << endl << “got out of first two layers” << endl;
}
else
{
ionCounter++;
}
}
if(neighborFlag == 1)
{
//cout << “Updating Neighbor Ions” << endl;
neighborIonsBCC[0] = scatterIonPos + lx - ly + lz;
neighborIonsBCC[1] = scatterIonPos + lx + ly + lz;
neighborIonsBCC[2] = scatterIonPos + lx + ly - lz;
neighborIonsBCC[3] = scatterIonPos + lx - ly - lz;
neighborIonsBCC[4] = scatterIonPos + lx * 2;
neighborIonsBCC[5] = scatterIonPos - lx - ly - lz;
neighborIonsBCC[6] = scatterIonPos - lx + ly - lz;
neighborIonsBCC[7] = scatterIonPos - lx + ly + lz;
neighborIonsBCC[8] = scatterIonPos - lx - ly + lz;
neighborIonsBCC[9] = scatterIonPos + lz * 2;
neighborIonsBCC[10] = scatterIonPos - lz * 2;
neighborIonsBCC[11] = scatterIonPos + ly * 2;
neighborIonsBCC[12] = scatterIonPos - ly * 2;
neighborIonsBCC[13] = scatterIonPos - lx * 2;
}
//set DiPrev to Di
DiPrev = Di;
//update current lambda to lambdaPrime
lambda = lambdaPrime;
//now the while condition of the mother do loop checks if the particle has lesser
energy than our lowest energy limit, ef.
}
while(e > ef);
//since we are out of the mother do loop now, the particle must have come to a
stop. So, increase the final particle distributions if the particle has not been
transmitted or backscattered.
if( ((transmitted == 0)) && ((backscattered == 0)) && ((insideChannel == 1)) )
{
ip = (int)(pl/cw + 1.0);
if(ip > 100) ip = 100;
//ipl[ip] = ipl[ip] + 1;
xsum = xsum + Di.x;
//my own bin function
selectedXBin = whichBin(Di.x, xx[Layer], numXBin);
//write the selected bin to the output file
//outStream << selectedXBin << endl;
//cout << x << endl << xx[Layer] << endl << numXBin << endl << selectedXBin;
xBin[selectedXBin] = xBin[selectedXBin] + 1;
//print final x value for plotting histogram
//cout << “ion “ << ih << “ final x: “ << Di.x << endl;
infoStream << “ion “ << ih << “ final x: “ << Di.x << endl;
//cout << Di.x << “,”;
rangeStream << Di.x << endl;
plsum = plsum + pl;
icsum = icsum + ic;
//ipl is the ion path length - the total avg. distance the ion travels
regardless of direction before it comes to stop
}
//that brings us to the end of one ion’s journey, now go to next ion by going back
to the for loop’s beginning..
}
//and this ends the monte carlo loop function. Take care of necessary structures and
variables that need to be cleared/deleted
outStream.close();
scatterStream.close();
infoStream << “Number of Backscattered Ions: “ << ib << endl;
infoStream.close();
rangeStream.close();
}
int whichNonUniformBin(double e, double arr[], int numBins)
{
double low = 0, high = arr[0];
if((e>=low) && (e<high))
return 0;
else
{
for(int i = 0; i < numBins; i++)
{
low += arr[i];
high += arr[i+1];
//cout << “\tlow: “ << low << “, high:” << high << endl;
if((e>=low) && (e<high))
return i;
}
}
}
140
//============================================================================
// Name : monte.cpp
// Author : Nazmus Saquib
// Version :
// Copyright :
// Description : BCA code in C++
//============================================================================
#include “Globals.h”
#include “scoef.h”
#include “rstop.h”
#include “muscle_bca.h”
#include “vectorGeometry.h”
const int numXBin = 100;
const int numIons = 1;
int xBin[numXBin+1] = {0};
int selectedXBin = 0;
double rho[4]={0.0};
int n[]={0,0,0,0};
double e0kev, m1, cw, ed, latticeConst;
int z1, hn, iy, nowout;
double dx[3] = {0.0};
int zt[3][7] = {0};
double mt[3][7] = {0.};
double t[3][7] = {0.};
int Layer; //use this for number of layers rather than the L in the program;
//remember this cannot be set to 0. Other loops/arrays may start from
//0, but keep this >= 1;
//the arrays..
double my[3][7]= {0},
ai[3][7]= {0},
fi[3][7]= {0},
ec[3][7]= {0},
io[3][7]= {0},
k[3]= {0},
kl[3][7]= {0};
double vf[3][7]= {0},
mu[3]= {0},
ioniz[3]= {0},
h[3]= {0},
xx[3]= {0},
m2[3]= {0.0},
z2[3]= {0},
c[3]= {0},
epsbk[3]= {0},
arho[3]= {0};
double a[3]= {0},
f[3]= {0},
lm[3]= {0},
pmax[3]= {0},
fd[3]= {0},
kd[3]= {0},
sbk[3]= {0},
lf[3]= {0},
yy[8]= {0};
double se[3][1000]= {0.0},
seo[1000]= {0.0},
epsdg[3]= {0.0};
double ls = 0., lo = 0., maximum = 0.;
double xsum = 0, x2sum = 0, x3sum = 0, x4sum = 0, plsum = 0, pl2sum = 0;
double avex = 0, vari = 0, sigma = 0, v = 0, v2 = 0, Gamma = 0, beta = 0, y = 0, avepl
= 0, sigpl = 0, avecol = 0;
int i = 0, j = 0;
int ib = 0, it = 0;
double eb = 0.0, et = 0.0;
int icsum = 0;
double y2sum = 0, xy2sum = 0, x2y2su = 0, y4sum = 0;
double tau = 0;
int iii = -1;
//my dummy vars
int w; double q;
//my customized data structures or vars
scoefData scoefz1;
rstopData rstp;
//these vars (continuing from this line) are added later as needed, vars that were not
declared in the initialization of trim85 but showed up in the middle.
double e0, ef;
int iz;
double alfa, alpha;
double tmin, da;
double L0;
int iz1;
double ee;
int izt;
double nh;
double epso;
int ih;
double e;
//boolean for keeping track of a particle being transmitted or backscattered
int transmitted = 0;
int backscattered = 0;
//boolean for keeping track of channeling
int insideChannel = 1;
//boolean for determining whether to scatter from neighbor atoms
int neighborFlag = 0;
//main function
int main()
{
cout << “Initializing” << endl;
Initialize(“IronInput.dat”);
calculateAvgMassOfLayer();
getStoppingForTarget();
setInitialConditions();
MonteCarlo();
/* *********************** Testing Ground for arrays and variables
******************** */
for (w = 1; w <= 8; w++) cout << “\t “ << yy[w];
for (w = 1; w <= 3; w++) cout << “\n\t “ << xx[w];
cout << “CW or L0: “ << L0;
//(trouble! The values of n[] elements are changing like crazy)
cout << endl << n[0] << “\t” << n[1] << “\t” << n[2] << “\t” << n[3] << endl;
cout << endl << rho[0] << “\t” << rho[1] << “\t” << rho[2] << “\t” << rho[3] <<
“\t” << rho[4] << endl;
//test z2[], m2[] arrays
for (w = 1; w <= Layer; w++) cout << “\t “ << z2[w];
for (w = 1; w <= Layer; w++) cout << “\n\t “ << m2[w];
//test the se values
cout << endl << se[1][1000] << “ “ << se[2][1000] << “ “ << se[3][1000] << endl;
//test the se[] values by printing 10th element from the array (to be implemented)
//for (w = 1; w <= 100; w++)
//{
//for (int sss = 1; sss <= 50; sss++)
//{
//cout << “\t” << mpart[w][sss];
//}
//}
/* *********************** End of Testing Ground ************************** */
cout << endl;
//Now print values of each bin in xBin
//for (w = 1; w <= numXBin; w++) cout << xBin[w] << “,”;
//print final x values
cout << endl;
cout << “Number of Backscattered Ions: “ << ib << endl;
cout << “Number of Transmitted Ions: “ << it << endl;
return 0;
}
//end of main
//Helper functions follow from here
//initialize variables and setup each layer over here
void Initialize(char* filename)
{
//Read command file
ifstream instream;
instream.open(filename,ios::in);
cout << filename;
if (!instream)
{
exitOnError(filename);
}
instream >> e0kev >> z1 >> m1 >> latticeConst >> hn >> cw >> ed >> iy >> nowout;
instream >> dx[1] >> rho[1];
instream >> zt[1][1] >> mt[1][1] >> t[1][1];
instream >> n[1];
instream >> dx[2] >> rho[2];
instream >> zt[2][1] >> mt[2][1] >> t[2][1];
instream >> n[2];
instream >> dx[3] >> rho[3];
instream >> zt[3][1] >> mt[3][1] >> t[3][1];
instream >> n[3];
for (w = 0; w <= 3; w++)
{ if (n[w] != 1) n[w] = 1; }
instream.close();
Layer = 3;
//done with primary (crude) setup, off to reading scoef.dat file
iz = z1;
getstructScoef(iz, scoefz1, “scoef1.dat”); //used to get pcoef data yy in trim85
//so we put the values in yy here immediately
for (w = 1; w <= 8; w++)
{ yy[w] = scoefz1.pcoef[w]; }
//note: although yy turns out to be just a dummy array
e0 = e0kev*1000; //convert to ev.
if (ed == 0.) ed = 25.0;
ef = Max(5.0, e0kev*0.1);
//alfa = angle of incidence, alpha = radian of alfa
alfa = 0.;
alpha = alfa*Pi/180;
tmin = 5.0;
tau = 0.0;
da = 3.0;
if (iy == 0) iy = 16381;
//now calculate the total depth of each layer = xx(l), and grid spacing cw
xx[1] = dx[1];
for (w = 2; w <= 3; w++) { xx[w] = dx[w] + xx[w-1]; }
if (cw == 0) cw = 0.01*xx[3];
L0 = cw;
//take care of any custom variable or struct I made
rstp.vfermi = 0.0; //set this to 0. for the time being (see log for explanation)
//now, off to avg mass of layer in the next void function
}
//avg mass and atomic number of each layer
void calculateAvgMassOfLayer()
{
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
h[LL] = h[LL] + t[LL][w];
//cout << “testing here..” << rstp.vfermi << endl;
}
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
t[LL][w] = t[LL][w]/h[LL];
m2[LL] = m2[LL] + t[LL][w] * mt[LL][w];
z2[LL] = z2[LL] + t[LL][w] * zt[LL][w];
//note: z2 wont be an integer once t has a value other than 1.0??
//so are we calculating average atomic number here? why?
}
}
//done with this, off to finding electronic stopping powers in the next function
}
void getStoppingForTarget()
{
iz1 = z1; ee = 0;
for (int LL = 1; LL <= Layer; LL++)
{
arho[LL] = rho[LL] * 0.6022/(m2[LL]);
mu[LL] = m1/(m2[LL]);
int ii = n[LL];
for (int nn = 1; nn <= ii; nn++)
{
//set rstp.se[1..1000] = 0. Clear it for the next loop
for (w = 1; w <= 1000; w++)
{ rstp.se[w] = 0.; }
izt = zt[LL][nn];
//calling getrstop now. units, lfctr, vfermi = 1 (doesnt matter)
getrStop(iz1, izt, e0kev, 1, 1., 1., rstp); //rstp defined in header
//set this anyway, though I dont calculate this in RSTOP
vf[LL][nn] = rstp.vfermi; //which is just set 0 in the struct def.
for (w = 1; w <= 1000; w++)
{
se[LL][w] = se[LL][w] + rstp.se[w] * t[LL][nn] * arho[LL];
}
}
}
//now, off to setting up initial conditions next function
}
void setInitialConditions()
{
nh = hn; //number of histories
for (int LL = 1; LL <= Layer; LL++)
{
a[LL] = 0.5292 * 0.8853 / ( pow(z1, 0.23) + pow(z2[LL], 0.23) );
//now calculate the mean flight path with the conditions given in trim85
f[LL] = a[LL] * m2[LL] / ( z1 * z2[LL] * 14.4 * (m1 + m2[LL] ) );
epso = e0 * f[LL];
epsdg[LL] = tmin * f[LL] * pow( (1.0 + mu[LL]) , 2) / (4.0 * mu[LL]);
fd[LL] = 0.01 * pow( z2[LL], (-7.0/3.0) );
kd[LL] = 0.1334 * pow ( z2[LL], (2.0/3.0) ) / sqrt( m2[LL] );
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
my[LL][w] = m1/mt[LL][w];
ec[LL][w] = 4.0 * my[LL][w] / pow( ( 1.0 + my[LL][w] ), 2);
ai[LL][w] = 0.5292 * 0.8853 / ( pow(z1,0.23) + pow(zt[LL][w],0.23) );
fi[LL][w] = ai[LL][w] * mt[LL][w] / ( z1 * zt[LL][w] * 14.4 * ( m1 + mt[LL][w] ) );
}
}
cout << “Setup finished. Starting Monte Carlo Loops..”;
//off to monte carlo loop in next routine
}
void MonteCarlo()
{
//custom variables and arrays for this section
double e;
double cosin = 0.0, siny = 0.0, sine = 0.0, cosy = 0.0;
double pl = 0.0;
int ic;
int LL = 1;
double eps;
double eeg;
double p;
double b;
int ie, ia; //not sure if ie or ia should be double. They are used to access elements
of the m[][] array at some point
double see;
double dee;
double s2, c2, ct, st;
double r, rr;
double ex1, ex2, ex3, ex4;
double v, v1;
double fr, fr1;
double q;
double roc, sqe;
double cc, aa, ff;
double delta, co;
double den;
double phi, psi;
double x1;
int ip;
//variables for crystal calculations
double sep = 0.0;
int ionCounter = 0;
double p1, p2;
double Theta = 0.0;
double rTheta = 0.0, rPhi = 0.0;
double thetaThreshold = 0.5;
double crystalMuonY = 0.0, crystalMuonZ = 0.0;
//amount of translations in y and z axes
double translationY = 0.0, translationZ = 0.0;
//Scatter Plot variables
const int numScatterPlotBins = 5;
double scatterPlot[numScatterPlotBins + 1] = {0.0};
//Vector declarations
//lattice constant of Target (input from file)
double latticeConstant = latticeConst;
Vector3 ions[4];
Vector3 ionsOrdered[4];
Vector3 neighborIonsBCC[14];
Vector3 neighborIonsFCC[14];
Vector3 ionTranslationY(0,translationY,0);
Vector3 ionTranslationZ(0,0,translationZ);
Vector3 unitzplus, unitzminus, unityplus, unityminus, unitxplus, unitxminus;
unitzplus.z = 1;
unitzminus.z = -1;
unityplus.y = 1;
unityminus.y = -1;
unitxplus.x = 1;
unitxminus.x = -1;
Vector3 initialDirection(1,0,0);
Vector3 d;
d.x = 1;
d *= latticeConstant/2;
Vector3 lx(latticeConstant/2, 0, 0);
Vector3 ly(0, latticeConstant/2, 0);
Vector3 lz(0, 0, latticeConstant/2);
Vector3 lambda;
Vector3 lambdaPrime;
Vector3 pVector;
Vector3 pUnitVector;
Vector3 sepVector;
Vector3 Di;
Vector3 DiPrev;
//Vector3 DiPrevToDi;
Vector3 delX;
Vector3 delX1, delX2;
Vector3 dummy1, dummy2, temp;
Vector3 scatterIonPos;
//initialize the random number generator
srand(time(NULL));
//open file to write output
ofstream outStream;
outStream.open(“coords0.txt”);
if(outStream.fail())
{
exitOnError(“Could not open Output file”);
}
//write basic information in the output file
//number of ions, ion energy, total depth, depth of each layer
outStream << nh << “\t” << e0kev << “\t” << xx[Layer] << “\t” << dx[1] << “\t”
<< dx[2] << “\t” << dx[3] << endl;
//open scatter plot file to write current Y and Z coordinates of muons at designated
intervals
ofstream scatterStream;
scatterStream.open(“scatterOut1.txt”);
if(scatterStream.fail())
{
exitOnError(“Could not open Scatter Plot Output file”);
}
//open range distribution file to write final X coordinates of muons
ofstream rangeStream;
rangeStream.open(“rangeOut1.txt”);
if(rangeStream.fail())
{
exitOnError(“Could not open Range Distribution Output file”);
}
//Open general information dump file
ofstream infoStream;
infoStream.open(“info1.txt”);
if(infoStream.fail())
{
exitOnError(“Could not open general information Output file”);
}
//Entering the target
//First set up for the top layer
for (ih = 1; ih <= nh; ih++)
{
avex = xsum / Max(1.0, (float)(ih - ib - it - 1));
if (talk == 2) cout << “Average ion range so far: “ << avex << “ angstroms.”
<<endl;
if (talk > 2) cout << “Now starting ion number “ << ih << endl;
e = e0;
//set scatterPlot array (the intervals)
scatterPlot[0] = 10;
scatterPlot[1] = 30;
scatterPlot[2] = 50;
scatterPlot[3] = 100;
scatterPlot[4] = 150;
scatterPlot[5] = 200;
/*
for(int ccc = 0; ccc <= numScatterPlotBins; ccc++)
{
cout << “scatter plot “ << ccc << “: “ << scatterPlot[ccc] << endl;
}
*/
//Initial Ion Positions
ions[0] = d + ionTranslationZ + unitzminus * (latticeConstant/2);
ions[1] = d + ionTranslationZ + unitzplus * (latticeConstant/2);
ions[2] = d * 2 + ionTranslationY + unityminus * (latticeConstant/2);
ions[3] = d * 2 + ionTranslationY + unityplus * (latticeConstant/2);
//Create a polygon that resides on the lateral axes.
//The points are put on anticlockwise order, which is important for
//testing whether the test point lies on this polygon
ionsOrdered[0] = ions[0];
ionsOrdered[1] = ions[2];
ionsOrdered[2] = ions[1];
ionsOrdered[3] = ions[3];
//generate random theta and phi angles.
rTheta = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * thetaThreshold;
rPhi = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * 2 * Pi;
//find corresponding x, y and z components of the direction vector.
//radius of the direction vector is 1
initialDirection.x = cos(rTheta);
initialDirection.z = sin(rTheta) * cos(rPhi);
initialDirection.y = sin(rTheta) * sin(rPhi);
//set the counter to 0 for a new ion
ionCounter = 0;
pl = 0.0;
ic = 0;
//set initial DiPrev - the origin
DiPrev.x = 0.0; DiPrev.y = 0.0; DiPrev.z = 0.0;
//set initial lambda, the direction of motion. Normalize it.
lambda.clear();
lambda = initialDirection;
lambda.normalize();
//set initial delX to origin
delX.clear();
//clear the dummy delX vectors, set them to origin
delX1.clear();
delX2.clear();
dummy1.clear();
dummy2.clear();
temp.clear();
LL = 1;
//set transmitted and backscattered to false
transmitted = 0;
backscattered = 0;
//set channeling to true
insideChannel = 1;
neighborFlag = 0;
//write the initial coordinates to the output file
outStream << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << endl << “Initial: “;
//cout << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << “r1 = “ << r1 << endl;
//cycle for each collision until the energy of the particle becomes too low, or
the particle backscatters, or it goes out of the last layer (transmission)
//needs a do while loop here,
//which I will mention as the ‘mother loop’ from now.
do
{
ic = ic + 1;
eps = e * f[LL];
eeg = sqrt(eps*epsdg[LL]);
//pmax[LL] = a[LL] / (eeg + sqrt(eeg) + 0.125 * pow( eeg, 0.1) );
pmax[LL] = sqrt(3) * (latticeConstant / 2) * 0.7;
//Calculate impact parameter and choose the atom to scatter from.
//Do this for ion pairs 0,1 and 2,3.
if (ionCounter == 0)
{
delX1 = ions[0] - DiPrev;
delX2 = ions[1] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[0];
ions[0] = ions[1];
ions[1] = temp;
//cout << “Vertical Ions swapped” << endl;
}
}
if (ionCounter == 2)
{
delX1 = ions[2] - DiPrev;
delX2 = ions[3] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[2];
ions[2] = ions[3];
ions[3] = temp;
//cout << “Horizontal Ions swapped” << endl;
}
}
//now calculate impact parameter
if(neighborFlag == 0)
{
delX = ions[ionCounter] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
else if(neighborFlag == 1)
{
double impact[13] = {0.0};
double radial[13] = {0.0};
double S[13] = {0.0};
double sumS = 0.0;
double Probability[13] = {0.0};
double rnd_candidate = 0.0;
int selected_candidate = -1;
for(int ncount = 0; ncount <= 13; ncount++)
{
delX = neighborIonsBCC[ncount] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
//scatterIonPos = neighborIonsBCC[ncount];
impact[ncount] = p;
radial[ncount] = delX.magnitude();
S[ncount] = 1 / ( pow(impact[ncount],2) * radial[ncount] );
sumS += S[ncount];
//general scheme of selecting the neighbor ion
// if(p < pmax[LL])
// {
// scatterIonPos = neighborIonsBCC[ncount];
// //cout << “Neighbor “ << ncount << “ is selected” << endl;
// break;
// }
}
for(int ncount = 0; ncount <= 13; ncount++)
{
Probability[ncount] = S[ncount] / sumS;
}
//print out the probability array
cout << endl;
for(int ncount = 0; ncount <= 13; ncount++)
{
//cout << Probability[ncount] << “ “;
infoStream << Probability[ncount] << “ “;
}
infoStream << endl;
//cout << endl;
//random number between 0 and 1
rnd_candidate = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) );
//cout << “rand_candidate: “ << rnd_candidate << endl;
//choose the candidate for scattering
selected_candidate = whichNonUniformBin(rnd_candidate, Probability, 13);
//cout << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate <<
endl;
infoStream << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate
<< endl;
//assign the scatterIonPos variable to the selected neighbor
scatterIonPos = neighborIonsBCC[selected_candidate];
//cout << “Scattering Ion Position: “; scatterIonPos.printVector();
//find the essential quantities for the selected neighbor
delX = neighborIonsBCC[selected_candidate] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
//find eps and b using fi[LL][nn], using nn that I was supposed to find from above
//here im deliberately using nn = 1
eps = fi[LL][1] * e;
b = p / ai[LL][1];
if (eps > 10) //rutherford scattering
{
s2 = 1.0 / (1.0 + (1.0 + b * (1.0 + b)) * pow((2.0 * eps * b), 2) );
c2 = 1.0 - s2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
else //magic formula
{
r = b;
rr = -2.7 * log(eps * b);
if (rr >= b)//note >= sign instead < in trim85
{
rr = -2.7 * log(eps * rr);
if (rr >= b)//note >= sign instead < in trim85
{
r = rr;
}
}
//do while loop that replaces line 330 loop
do
{
ex1 = 0.18175 * exp(-3.1998 * r);
ex2 = 0.50986 * exp(-0.94229 * r);
ex3 = 0.28022 * exp(-0.4029 * r);
ex4 = 0.028171 * exp(-0.20162 * r);
v = (ex1 + ex2 + ex3 + ex4) / r;
v1 = -(v + 3.1998 * ex1 + 0.94229 * ex2 + 0.4029 * ex3 + 0.20162 * ex4) / r;
fr = b * b / r + v * r / eps - r;
fr1 = -b * b / (r * r) + (v + v1 * r) / eps - 1.0;
q = fr / fr1;
r = r - q;
}
while( (Abs(q / r)) > 0.001 );
roc = -2.0 * (eps - v) / v1;
sqe = sqrt(eps);
//5 parameter magic scattering calculation
//below is for universal potential
cc = (0.011615 + sqe) / (0.0071222 + sqe);
aa = 2.0 * eps * (1.0 + (0.99229 / sqe) ) * ( pow(b, cc) );
ff = ( sqrt(aa * aa + 1.0) - aa) * ( (9.3066 + eps) / (14.813 + eps) );
delta = (r - b) * aa * ff / (ff + 1.0);
co = (b + delta + roc) / (r + roc);
c2 = co * co;
s2 = 1.0 - c2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
Theta = acos(ct);
//we are done finding theta (in CM system). So calculate all other quantities.
//find separation and the separation vector.
phi = (Pi - Theta) / 2;
sep = p / tan(phi);
sepVector = lambda * sep;
//find theta in laboratory frame - psi
psi = atan(st / (ct + my[LL][1] ) );
//note: change my[LL][1] to my[LL][nn] when the above section is fixed.
if (psi < 0 ) psi = psi + Pi; //should I do this for crystals?
//find Di, the scattering point vector
Di = DiPrev + delX + pVector - sepVector;
//find new direction of motion
lambdaPrime = lambda * cos(psi) + pUnitVector * sin(psi);
lambdaPrime.normalize();
//find length of step, ls = distance of Di from DiPrev
ls = Di.getDistance(DiPrev);
//find energy lost due to electronic stopping, dee
ie = (int)(e/e0kev+0.5); //should it be 0.5? or less so that ie <=1000?
see = se[LL][ie];
if (e < e0kev) see = se[LL][1] * sqrt(e/e0kev);
dee = ls * see;
// den = energy transferred to recoil
den = ec[LL][1] * s2 * e; //note: I am using ec[LL][1] here instead of [LL][nn].
//cout << “den = “ << den << “, dee = “ << dee << endl;
infoStream << “den = “ << den << “, dee = “ << dee << endl;
e = e - den - dee;
//cout << endl<< “current ion energy: “ << e << endl;
if (dee > maximum) maximum = dee;
pl = pl + ls - tau;
//write the ion position to output file
outStream << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
if((ic%30)==0)
{
//cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
}
//determine which scatter plot Di’s x value belongs to.
//output the y and z coordinates to scatter plot file accordingly.
for(int cc = 0; cc <= numScatterPlotBins; cc++)
{
if( Di.x >= (scatterPlot[cc]) )
{
crystalMuonY = Di.y - translationY;
crystalMuonZ = Di.z - translationZ;
//cout << “scatter plot “ << ct << “: “ << scatterPlot[ct] << endl;
scatterStream << scatterPlot[cc] << “\t” << crystalMuonY << “\t” <<
crystalMuonZ << endl;
//set scatterPlot[ss] to a big number
scatterPlot[cc] = 10000;
//break out of this for loop
break;
}
}
//determine if Di is in the channeling region.
//insideChannel = Di.isInsidePolygon(ionsOrdered, 4);
//break out of parent loop if not inside the channel
if(insideChannel == 0)
{
cout << “Ion “ << ih << “ is out of Channel” << endl;
cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
break;
}
//determine which layer the next collision will be in
if (Di.x < 0.0) //particle is backscattered
{
backscattered = 1; //cout << “ion number “ << ih << “ backscattered.” << endl;
infoStream << “ion number “ << ih << “ backscattered.” << endl;
ib = ib + 1;
eb = eb + e;
break; //break out of ‘mother do loop’ and continue with the next session of
for loop.
}
//here we set the current or next layer the particle will be in
for (w = 1; w <= Layer; w++)
{
if ( (Di.x <= xx[w]) && (w == 1) )
{
LL = 1;
//cout << endl<<”ion is in layer “ << LL << endl;
break;
//break out of this For loop and go check if the particle is transmitted.
}
else if ( (Di.x <= xx[w]) && (Di.x > xx[w-1]) )
{
LL = w;
//cout << “ion is in layer “ << LL <<endl;
break; //break out of this For loop and go check if the particle is
transmitted.
}
}
//now, check for particle transmission, i.e. whether the particle went out of the
last layer.
if(Di.x >= xx[Layer])
{
//particle is transmitted, take care of appropriate variables and break
transmitted = 1;//cout << “ion number “ << ih << “ transmitted.” << endl;
it = it + 1;
et = et + e;
ia = 57.295779 * acos(cosin) / da + 1.0;
ie = 100 * e / e0 + 1.0;
//m[ie][ia] = m[ie][ia] + 1;//note: how is this possible? ie and ia should be
integers in order to access the elements of the array m[][]. But we calculate them as
doubles here!
break; //break out of the ‘mother’ do loop
}
//now take care of ionCounter and other variables for the next scattering
if(neighborFlag == 0)
{
if(ionCounter == 3)
{
//ionCounter = 0;
neighborFlag = 1;
scatterIonPos = ions[3];
//cout << endl << “got out of first two layers” << endl;
}
else
{
ionCounter++;
}
}
if(neighborFlag == 1)
{
//cout << “Updating Neighbor Ions” << endl;
neighborIonsBCC[0] = scatterIonPos + lx - ly + lz;
neighborIonsBCC[1] = scatterIonPos + lx + ly + lz;
neighborIonsBCC[2] = scatterIonPos + lx + ly - lz;
neighborIonsBCC[3] = scatterIonPos + lx - ly - lz;
neighborIonsBCC[4] = scatterIonPos + lx * 2;
neighborIonsBCC[5] = scatterIonPos - lx - ly - lz;
neighborIonsBCC[6] = scatterIonPos - lx + ly - lz;
neighborIonsBCC[7] = scatterIonPos - lx + ly + lz;
neighborIonsBCC[8] = scatterIonPos - lx - ly + lz;
neighborIonsBCC[9] = scatterIonPos + lz * 2;
neighborIonsBCC[10] = scatterIonPos - lz * 2;
neighborIonsBCC[11] = scatterIonPos + ly * 2;
neighborIonsBCC[12] = scatterIonPos - ly * 2;
neighborIonsBCC[13] = scatterIonPos - lx * 2;
}
//set DiPrev to Di
DiPrev = Di;
//update current lambda to lambdaPrime
lambda = lambdaPrime;
//now the while condition of the mother do loop checks if the particle has lesser
energy than our lowest energy limit, ef.
}
while(e > ef);
//since we are out of the mother do loop now, the particle must have come to a
stop. So, increase the final particle distributions if the particle has not been
transmitted or backscattered.
if( ((transmitted == 0)) && ((backscattered == 0)) && ((insideChannel == 1)) )
{
ip = (int)(pl/cw + 1.0);
if(ip > 100) ip = 100;
//ipl[ip] = ipl[ip] + 1;
xsum = xsum + Di.x;
//my own bin function
selectedXBin = whichBin(Di.x, xx[Layer], numXBin);
//write the selected bin to the output file
//outStream << selectedXBin << endl;
//cout << x << endl << xx[Layer] << endl << numXBin << endl << selectedXBin;
xBin[selectedXBin] = xBin[selectedXBin] + 1;
//print final x value for plotting histogram
//cout << “ion “ << ih << “ final x: “ << Di.x << endl;
infoStream << “ion “ << ih << “ final x: “ << Di.x << endl;
//cout << Di.x << “,”;
rangeStream << Di.x << endl;
plsum = plsum + pl;
icsum = icsum + ic;
//ipl is the ion path length - the total avg. distance the ion travels
regardless of direction before it comes to stop
}
//that brings us to the end of one ion’s journey, now go to next ion by going back
to the for loop’s beginning..
}
//and this ends the monte carlo loop function. Take care of necessary structures and
variables that need to be cleared/deleted
outStream.close();
scatterStream.close();
infoStream << “Number of Backscattered Ions: “ << ib << endl;
infoStream.close();
rangeStream.close();
}
int whichNonUniformBin(double e, double arr[], int numBins)
{
double low = 0, high = arr[0];
if((e>=low) && (e<high))
return 0;
else
{
for(int i = 0; i < numBins; i++)
{
low += arr[i];
high += arr[i+1];
//cout << “\tlow: “ << low << “, high:” << high << endl;
if((e>=low) && (e<high))
return i;
}
}
}
141
//============================================================================
// Name : monte.cpp
// Author : Nazmus Saquib
// Version :
// Copyright :
// Description : BCA code in C++
//============================================================================
#include “Globals.h”
#include “scoef.h”
#include “rstop.h”
#include “muscle_bca.h”
#include “vectorGeometry.h”
const int numXBin = 100;
const int numIons = 1;
int xBin[numXBin+1] = {0};
int selectedXBin = 0;
double rho[4]={0.0};
int n[]={0,0,0,0};
double e0kev, m1, cw, ed, latticeConst;
int z1, hn, iy, nowout;
double dx[3] = {0.0};
int zt[3][7] = {0};
double mt[3][7] = {0.};
double t[3][7] = {0.};
int Layer; //use this for number of layers rather than the L in the program;
//remember this cannot be set to 0. Other loops/arrays may start from
//0, but keep this >= 1;
//the arrays..
double my[3][7]= {0},
ai[3][7]= {0},
fi[3][7]= {0},
ec[3][7]= {0},
io[3][7]= {0},
k[3]= {0},
kl[3][7]= {0};
double vf[3][7]= {0},
mu[3]= {0},
ioniz[3]= {0},
h[3]= {0},
xx[3]= {0},
m2[3]= {0.0},
z2[3]= {0},
c[3]= {0},
epsbk[3]= {0},
arho[3]= {0};
double a[3]= {0},
f[3]= {0},
lm[3]= {0},
pmax[3]= {0},
fd[3]= {0},
kd[3]= {0},
sbk[3]= {0},
lf[3]= {0},
yy[8]= {0};
double se[3][1000]= {0.0},
seo[1000]= {0.0},
epsdg[3]= {0.0};
double ls = 0., lo = 0., maximum = 0.;
double xsum = 0, x2sum = 0, x3sum = 0, x4sum = 0, plsum = 0, pl2sum = 0;
double avex = 0, vari = 0, sigma = 0, v = 0, v2 = 0, Gamma = 0, beta = 0, y = 0, avepl
= 0, sigpl = 0, avecol = 0;
int i = 0, j = 0;
int ib = 0, it = 0;
double eb = 0.0, et = 0.0;
int icsum = 0;
double y2sum = 0, xy2sum = 0, x2y2su = 0, y4sum = 0;
double tau = 0;
int iii = -1;
//my dummy vars
int w; double q;
//my customized data structures or vars
scoefData scoefz1;
rstopData rstp;
//these vars (continuing from this line) are added later as needed, vars that were not
declared in the initialization of trim85 but showed up in the middle.
double e0, ef;
int iz;
double alfa, alpha;
double tmin, da;
double L0;
int iz1;
double ee;
int izt;
double nh;
double epso;
int ih;
double e;
//boolean for keeping track of a particle being transmitted or backscattered
int transmitted = 0;
int backscattered = 0;
//boolean for keeping track of channeling
int insideChannel = 1;
//boolean for determining whether to scatter from neighbor atoms
int neighborFlag = 0;
//main function
int main()
{
cout << “Initializing” << endl;
Initialize(“IronInput.dat”);
calculateAvgMassOfLayer();
getStoppingForTarget();
setInitialConditions();
MonteCarlo();
/* *********************** Testing Ground for arrays and variables
******************** */
for (w = 1; w <= 8; w++) cout << “\t “ << yy[w];
for (w = 1; w <= 3; w++) cout << “\n\t “ << xx[w];
cout << “CW or L0: “ << L0;
//(trouble! The values of n[] elements are changing like crazy)
cout << endl << n[0] << “\t” << n[1] << “\t” << n[2] << “\t” << n[3] << endl;
cout << endl << rho[0] << “\t” << rho[1] << “\t” << rho[2] << “\t” << rho[3] <<
“\t” << rho[4] << endl;
//test z2[], m2[] arrays
for (w = 1; w <= Layer; w++) cout << “\t “ << z2[w];
for (w = 1; w <= Layer; w++) cout << “\n\t “ << m2[w];
//test the se values
cout << endl << se[1][1000] << “ “ << se[2][1000] << “ “ << se[3][1000] << endl;
//test the se[] values by printing 10th element from the array (to be implemented)
//for (w = 1; w <= 100; w++)
//{
//for (int sss = 1; sss <= 50; sss++)
//{
//cout << “\t” << mpart[w][sss];
//}
//}
/* *********************** End of Testing Ground ************************** */
cout << endl;
//Now print values of each bin in xBin
//for (w = 1; w <= numXBin; w++) cout << xBin[w] << “,”;
//print final x values
cout << endl;
cout << “Number of Backscattered Ions: “ << ib << endl;
cout << “Number of Transmitted Ions: “ << it << endl;
return 0;
}
//end of main
//Helper functions follow from here
//initialize variables and setup each layer over here
void Initialize(char* filename)
{
//Read command file
ifstream instream;
instream.open(filename,ios::in);
cout << filename;
if (!instream)
{
exitOnError(filename);
}
instream >> e0kev >> z1 >> m1 >> latticeConst >> hn >> cw >> ed >> iy >> nowout;
instream >> dx[1] >> rho[1];
instream >> zt[1][1] >> mt[1][1] >> t[1][1];
instream >> n[1];
instream >> dx[2] >> rho[2];
instream >> zt[2][1] >> mt[2][1] >> t[2][1];
instream >> n[2];
instream >> dx[3] >> rho[3];
instream >> zt[3][1] >> mt[3][1] >> t[3][1];
instream >> n[3];
for (w = 0; w <= 3; w++)
{ if (n[w] != 1) n[w] = 1; }
instream.close();
Layer = 3;
//done with primary (crude) setup, off to reading scoef.dat file
iz = z1;
getstructScoef(iz, scoefz1, “scoef1.dat”); //used to get pcoef data yy in trim85
//so we put the values in yy here immediately
for (w = 1; w <= 8; w++)
{ yy[w] = scoefz1.pcoef[w]; }
//note: although yy turns out to be just a dummy array
e0 = e0kev*1000; //convert to ev.
if (ed == 0.) ed = 25.0;
ef = Max(5.0, e0kev*0.1);
//alfa = angle of incidence, alpha = radian of alfa
alfa = 0.;
alpha = alfa*Pi/180;
tmin = 5.0;
tau = 0.0;
da = 3.0;
if (iy == 0) iy = 16381;
//now calculate the total depth of each layer = xx(l), and grid spacing cw
xx[1] = dx[1];
for (w = 2; w <= 3; w++) { xx[w] = dx[w] + xx[w-1]; }
if (cw == 0) cw = 0.01*xx[3];
L0 = cw;
//take care of any custom variable or struct I made
rstp.vfermi = 0.0; //set this to 0. for the time being (see log for explanation)
//now, off to avg mass of layer in the next void function
}
//avg mass and atomic number of each layer
void calculateAvgMassOfLayer()
{
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
h[LL] = h[LL] + t[LL][w];
//cout << “testing here..” << rstp.vfermi << endl;
}
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
t[LL][w] = t[LL][w]/h[LL];
m2[LL] = m2[LL] + t[LL][w] * mt[LL][w];
z2[LL] = z2[LL] + t[LL][w] * zt[LL][w];
//note: z2 wont be an integer once t has a value other than 1.0??
//so are we calculating average atomic number here? why?
}
}
//done with this, off to finding electronic stopping powers in the next function
}
void getStoppingForTarget()
{
iz1 = z1; ee = 0;
for (int LL = 1; LL <= Layer; LL++)
{
arho[LL] = rho[LL] * 0.6022/(m2[LL]);
mu[LL] = m1/(m2[LL]);
int ii = n[LL];
for (int nn = 1; nn <= ii; nn++)
{
//set rstp.se[1..1000] = 0. Clear it for the next loop
for (w = 1; w <= 1000; w++)
{ rstp.se[w] = 0.; }
izt = zt[LL][nn];
//calling getrstop now. units, lfctr, vfermi = 1 (doesnt matter)
getrStop(iz1, izt, e0kev, 1, 1., 1., rstp); //rstp defined in header
//set this anyway, though I dont calculate this in RSTOP
vf[LL][nn] = rstp.vfermi; //which is just set 0 in the struct def.
for (w = 1; w <= 1000; w++)
{
se[LL][w] = se[LL][w] + rstp.se[w] * t[LL][nn] * arho[LL];
}
}
}
//now, off to setting up initial conditions next function
}
void setInitialConditions()
{
nh = hn; //number of histories
for (int LL = 1; LL <= Layer; LL++)
{
a[LL] = 0.5292 * 0.8853 / ( pow(z1, 0.23) + pow(z2[LL], 0.23) );
//now calculate the mean flight path with the conditions given in trim85
f[LL] = a[LL] * m2[LL] / ( z1 * z2[LL] * 14.4 * (m1 + m2[LL] ) );
epso = e0 * f[LL];
epsdg[LL] = tmin * f[LL] * pow( (1.0 + mu[LL]) , 2) / (4.0 * mu[LL]);
fd[LL] = 0.01 * pow( z2[LL], (-7.0/3.0) );
kd[LL] = 0.1334 * pow ( z2[LL], (2.0/3.0) ) / sqrt( m2[LL] );
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
my[LL][w] = m1/mt[LL][w];
ec[LL][w] = 4.0 * my[LL][w] / pow( ( 1.0 + my[LL][w] ), 2);
ai[LL][w] = 0.5292 * 0.8853 / ( pow(z1,0.23) + pow(zt[LL][w],0.23) );
fi[LL][w] = ai[LL][w] * mt[LL][w] / ( z1 * zt[LL][w] * 14.4 * ( m1 + mt[LL][w] ) );
}
}
cout << “Setup finished. Starting Monte Carlo Loops..”;
//off to monte carlo loop in next routine
}
void MonteCarlo()
{
//custom variables and arrays for this section
double e;
double cosin = 0.0, siny = 0.0, sine = 0.0, cosy = 0.0;
double pl = 0.0;
int ic;
int LL = 1;
double eps;
double eeg;
double p;
double b;
int ie, ia; //not sure if ie or ia should be double. They are used to access elements
of the m[][] array at some point
double see;
double dee;
double s2, c2, ct, st;
double r, rr;
double ex1, ex2, ex3, ex4;
double v, v1;
double fr, fr1;
double q;
double roc, sqe;
double cc, aa, ff;
double delta, co;
double den;
double phi, psi;
double x1;
int ip;
//variables for crystal calculations
double sep = 0.0;
int ionCounter = 0;
double p1, p2;
double Theta = 0.0;
double rTheta = 0.0, rPhi = 0.0;
double thetaThreshold = 0.5;
double crystalMuonY = 0.0, crystalMuonZ = 0.0;
//amount of translations in y and z axes
double translationY = 0.0, translationZ = 0.0;
//Scatter Plot variables
const int numScatterPlotBins = 5;
double scatterPlot[numScatterPlotBins + 1] = {0.0};
//Vector declarations
//lattice constant of Target (input from file)
double latticeConstant = latticeConst;
Vector3 ions[4];
Vector3 ionsOrdered[4];
Vector3 neighborIonsBCC[14];
Vector3 neighborIonsFCC[14];
Vector3 ionTranslationY(0,translationY,0);
Vector3 ionTranslationZ(0,0,translationZ);
Vector3 unitzplus, unitzminus, unityplus, unityminus, unitxplus, unitxminus;
unitzplus.z = 1;
unitzminus.z = -1;
unityplus.y = 1;
unityminus.y = -1;
unitxplus.x = 1;
unitxminus.x = -1;
Vector3 initialDirection(1,0,0);
Vector3 d;
d.x = 1;
d *= latticeConstant/2;
Vector3 lx(latticeConstant/2, 0, 0);
Vector3 ly(0, latticeConstant/2, 0);
Vector3 lz(0, 0, latticeConstant/2);
Vector3 lambda;
Vector3 lambdaPrime;
Vector3 pVector;
Vector3 pUnitVector;
Vector3 sepVector;
Vector3 Di;
Vector3 DiPrev;
//Vector3 DiPrevToDi;
Vector3 delX;
Vector3 delX1, delX2;
Vector3 dummy1, dummy2, temp;
Vector3 scatterIonPos;
//initialize the random number generator
srand(time(NULL));
//open file to write output
ofstream outStream;
outStream.open(“coords0.txt”);
if(outStream.fail())
{
exitOnError(“Could not open Output file”);
}
//write basic information in the output file
//number of ions, ion energy, total depth, depth of each layer
outStream << nh << “\t” << e0kev << “\t” << xx[Layer] << “\t” << dx[1] << “\t”
<< dx[2] << “\t” << dx[3] << endl;
//open scatter plot file to write current Y and Z coordinates of muons at designated
intervals
ofstream scatterStream;
scatterStream.open(“scatterOut1.txt”);
if(scatterStream.fail())
{
exitOnError(“Could not open Scatter Plot Output file”);
}
//open range distribution file to write final X coordinates of muons
ofstream rangeStream;
rangeStream.open(“rangeOut1.txt”);
if(rangeStream.fail())
{
exitOnError(“Could not open Range Distribution Output file”);
}
//Open general information dump file
ofstream infoStream;
infoStream.open(“info1.txt”);
if(infoStream.fail())
{
exitOnError(“Could not open general information Output file”);
}
//Entering the target
//First set up for the top layer
for (ih = 1; ih <= nh; ih++)
{
avex = xsum / Max(1.0, (float)(ih - ib - it - 1));
if (talk == 2) cout << “Average ion range so far: “ << avex << “ angstroms.”
<<endl;
if (talk > 2) cout << “Now starting ion number “ << ih << endl;
e = e0;
//set scatterPlot array (the intervals)
scatterPlot[0] = 10;
scatterPlot[1] = 30;
scatterPlot[2] = 50;
scatterPlot[3] = 100;
scatterPlot[4] = 150;
scatterPlot[5] = 200;
/*
for(int ccc = 0; ccc <= numScatterPlotBins; ccc++)
{
cout << “scatter plot “ << ccc << “: “ << scatterPlot[ccc] << endl;
}
*/
//Initial Ion Positions
ions[0] = d + ionTranslationZ + unitzminus * (latticeConstant/2);
ions[1] = d + ionTranslationZ + unitzplus * (latticeConstant/2);
ions[2] = d * 2 + ionTranslationY + unityminus * (latticeConstant/2);
ions[3] = d * 2 + ionTranslationY + unityplus * (latticeConstant/2);
//Create a polygon that resides on the lateral axes.
//The points are put on anticlockwise order, which is important for
//testing whether the test point lies on this polygon
ionsOrdered[0] = ions[0];
ionsOrdered[1] = ions[2];
ionsOrdered[2] = ions[1];
ionsOrdered[3] = ions[3];
//generate random theta and phi angles.
rTheta = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * thetaThreshold;
rPhi = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * 2 * Pi;
//find corresponding x, y and z components of the direction vector.
//radius of the direction vector is 1
initialDirection.x = cos(rTheta);
initialDirection.z = sin(rTheta) * cos(rPhi);
initialDirection.y = sin(rTheta) * sin(rPhi);
//set the counter to 0 for a new ion
ionCounter = 0;
pl = 0.0;
ic = 0;
//set initial DiPrev - the origin
DiPrev.x = 0.0; DiPrev.y = 0.0; DiPrev.z = 0.0;
//set initial lambda, the direction of motion. Normalize it.
lambda.clear();
lambda = initialDirection;
lambda.normalize();
//set initial delX to origin
delX.clear();
//clear the dummy delX vectors, set them to origin
delX1.clear();
delX2.clear();
dummy1.clear();
dummy2.clear();
temp.clear();
LL = 1;
//set transmitted and backscattered to false
transmitted = 0;
backscattered = 0;
//set channeling to true
insideChannel = 1;
neighborFlag = 0;
//write the initial coordinates to the output file
outStream << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << endl << “Initial: “;
//cout << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << “r1 = “ << r1 << endl;
//cycle for each collision until the energy of the particle becomes too low, or
the particle backscatters, or it goes out of the last layer (transmission)
//needs a do while loop here,
//which I will mention as the ‘mother loop’ from now.
do
{
ic = ic + 1;
eps = e * f[LL];
eeg = sqrt(eps*epsdg[LL]);
//pmax[LL] = a[LL] / (eeg + sqrt(eeg) + 0.125 * pow( eeg, 0.1) );
pmax[LL] = sqrt(3) * (latticeConstant / 2) * 0.7;
//Calculate impact parameter and choose the atom to scatter from.
//Do this for ion pairs 0,1 and 2,3.
if (ionCounter == 0)
{
delX1 = ions[0] - DiPrev;
delX2 = ions[1] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[0];
ions[0] = ions[1];
ions[1] = temp;
//cout << “Vertical Ions swapped” << endl;
}
}
if (ionCounter == 2)
{
delX1 = ions[2] - DiPrev;
delX2 = ions[3] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[2];
ions[2] = ions[3];
ions[3] = temp;
//cout << “Horizontal Ions swapped” << endl;
}
}
//now calculate impact parameter
if(neighborFlag == 0)
{
delX = ions[ionCounter] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
else if(neighborFlag == 1)
{
double impact[13] = {0.0};
double radial[13] = {0.0};
double S[13] = {0.0};
double sumS = 0.0;
double Probability[13] = {0.0};
double rnd_candidate = 0.0;
int selected_candidate = -1;
for(int ncount = 0; ncount <= 13; ncount++)
{
delX = neighborIonsBCC[ncount] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
//scatterIonPos = neighborIonsBCC[ncount];
impact[ncount] = p;
radial[ncount] = delX.magnitude();
S[ncount] = 1 / ( pow(impact[ncount],2) * radial[ncount] );
sumS += S[ncount];
//general scheme of selecting the neighbor ion
// if(p < pmax[LL])
// {
// scatterIonPos = neighborIonsBCC[ncount];
// //cout << “Neighbor “ << ncount << “ is selected” << endl;
// break;
// }
}
for(int ncount = 0; ncount <= 13; ncount++)
{
Probability[ncount] = S[ncount] / sumS;
}
//print out the probability array
cout << endl;
for(int ncount = 0; ncount <= 13; ncount++)
{
//cout << Probability[ncount] << “ “;
infoStream << Probability[ncount] << “ “;
}
infoStream << endl;
//cout << endl;
//random number between 0 and 1
rnd_candidate = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) );
//cout << “rand_candidate: “ << rnd_candidate << endl;
//choose the candidate for scattering
selected_candidate = whichNonUniformBin(rnd_candidate, Probability, 13);
//cout << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate <<
endl;
infoStream << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate
<< endl;
//assign the scatterIonPos variable to the selected neighbor
scatterIonPos = neighborIonsBCC[selected_candidate];
//cout << “Scattering Ion Position: “; scatterIonPos.printVector();
//find the essential quantities for the selected neighbor
delX = neighborIonsBCC[selected_candidate] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
//find eps and b using fi[LL][nn], using nn that I was supposed to find from above
//here im deliberately using nn = 1
eps = fi[LL][1] * e;
b = p / ai[LL][1];
if (eps > 10) //rutherford scattering
{
s2 = 1.0 / (1.0 + (1.0 + b * (1.0 + b)) * pow((2.0 * eps * b), 2) );
c2 = 1.0 - s2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
else //magic formula
{
r = b;
rr = -2.7 * log(eps * b);
if (rr >= b)//note >= sign instead < in trim85
{
rr = -2.7 * log(eps * rr);
if (rr >= b)//note >= sign instead < in trim85
{
r = rr;
}
}
//do while loop that replaces line 330 loop
do
{
ex1 = 0.18175 * exp(-3.1998 * r);
ex2 = 0.50986 * exp(-0.94229 * r);
ex3 = 0.28022 * exp(-0.4029 * r);
ex4 = 0.028171 * exp(-0.20162 * r);
v = (ex1 + ex2 + ex3 + ex4) / r;
v1 = -(v + 3.1998 * ex1 + 0.94229 * ex2 + 0.4029 * ex3 + 0.20162 * ex4) / r;
fr = b * b / r + v * r / eps - r;
fr1 = -b * b / (r * r) + (v + v1 * r) / eps - 1.0;
q = fr / fr1;
r = r - q;
}
while( (Abs(q / r)) > 0.001 );
roc = -2.0 * (eps - v) / v1;
sqe = sqrt(eps);
//5 parameter magic scattering calculation
//below is for universal potential
cc = (0.011615 + sqe) / (0.0071222 + sqe);
aa = 2.0 * eps * (1.0 + (0.99229 / sqe) ) * ( pow(b, cc) );
ff = ( sqrt(aa * aa + 1.0) - aa) * ( (9.3066 + eps) / (14.813 + eps) );
delta = (r - b) * aa * ff / (ff + 1.0);
co = (b + delta + roc) / (r + roc);
c2 = co * co;
s2 = 1.0 - c2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
Theta = acos(ct);
//we are done finding theta (in CM system). So calculate all other quantities.
//find separation and the separation vector.
phi = (Pi - Theta) / 2;
sep = p / tan(phi);
sepVector = lambda * sep;
//find theta in laboratory frame - psi
psi = atan(st / (ct + my[LL][1] ) );
//note: change my[LL][1] to my[LL][nn] when the above section is fixed.
if (psi < 0 ) psi = psi + Pi; //should I do this for crystals?
//find Di, the scattering point vector
Di = DiPrev + delX + pVector - sepVector;
//find new direction of motion
lambdaPrime = lambda * cos(psi) + pUnitVector * sin(psi);
lambdaPrime.normalize();
//find length of step, ls = distance of Di from DiPrev
ls = Di.getDistance(DiPrev);
//find energy lost due to electronic stopping, dee
ie = (int)(e/e0kev+0.5); //should it be 0.5? or less so that ie <=1000?
see = se[LL][ie];
if (e < e0kev) see = se[LL][1] * sqrt(e/e0kev);
dee = ls * see;
// den = energy transferred to recoil
den = ec[LL][1] * s2 * e; //note: I am using ec[LL][1] here instead of [LL][nn].
//cout << “den = “ << den << “, dee = “ << dee << endl;
infoStream << “den = “ << den << “, dee = “ << dee << endl;
e = e - den - dee;
//cout << endl<< “current ion energy: “ << e << endl;
if (dee > maximum) maximum = dee;
pl = pl + ls - tau;
//write the ion position to output file
outStream << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
if((ic%30)==0)
{
//cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
}
//determine which scatter plot Di’s x value belongs to.
//output the y and z coordinates to scatter plot file accordingly.
for(int cc = 0; cc <= numScatterPlotBins; cc++)
{
if( Di.x >= (scatterPlot[cc]) )
{
crystalMuonY = Di.y - translationY;
crystalMuonZ = Di.z - translationZ;
//cout << “scatter plot “ << ct << “: “ << scatterPlot[ct] << endl;
scatterStream << scatterPlot[cc] << “\t” << crystalMuonY << “\t” <<
crystalMuonZ << endl;
//set scatterPlot[ss] to a big number
scatterPlot[cc] = 10000;
//break out of this for loop
break;
}
}
//determine if Di is in the channeling region.
//insideChannel = Di.isInsidePolygon(ionsOrdered, 4);
//break out of parent loop if not inside the channel
if(insideChannel == 0)
{
cout << “Ion “ << ih << “ is out of Channel” << endl;
cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
break;
}
//determine which layer the next collision will be in
if (Di.x < 0.0) //particle is backscattered
{
backscattered = 1; //cout << “ion number “ << ih << “ backscattered.” << endl;
infoStream << “ion number “ << ih << “ backscattered.” << endl;
ib = ib + 1;
eb = eb + e;
break; //break out of ‘mother do loop’ and continue with the next session of
for loop.
}
//here we set the current or next layer the particle will be in
for (w = 1; w <= Layer; w++)
{
if ( (Di.x <= xx[w]) && (w == 1) )
{
LL = 1;
//cout << endl<<”ion is in layer “ << LL << endl;
break;
//break out of this For loop and go check if the particle is transmitted.
}
else if ( (Di.x <= xx[w]) && (Di.x > xx[w-1]) )
{
LL = w;
//cout << “ion is in layer “ << LL <<endl;
break; //break out of this For loop and go check if the particle is
transmitted.
}
}
//now, check for particle transmission, i.e. whether the particle went out of the
last layer.
if(Di.x >= xx[Layer])
{
//particle is transmitted, take care of appropriate variables and break
transmitted = 1;//cout << “ion number “ << ih << “ transmitted.” << endl;
it = it + 1;
et = et + e;
ia = 57.295779 * acos(cosin) / da + 1.0;
ie = 100 * e / e0 + 1.0;
//m[ie][ia] = m[ie][ia] + 1;//note: how is this possible? ie and ia should be
integers in order to access the elements of the array m[][]. But we calculate them as
doubles here!
break; //break out of the ‘mother’ do loop
}
//now take care of ionCounter and other variables for the next scattering
if(neighborFlag == 0)
{
if(ionCounter == 3)
{
//ionCounter = 0;
neighborFlag = 1;
scatterIonPos = ions[3];
//cout << endl << “got out of first two layers” << endl;
}
else
{
ionCounter++;
}
}
if(neighborFlag == 1)
{
//cout << “Updating Neighbor Ions” << endl;
neighborIonsBCC[0] = scatterIonPos + lx - ly + lz;
neighborIonsBCC[1] = scatterIonPos + lx + ly + lz;
neighborIonsBCC[2] = scatterIonPos + lx + ly - lz;
neighborIonsBCC[3] = scatterIonPos + lx - ly - lz;
neighborIonsBCC[4] = scatterIonPos + lx * 2;
neighborIonsBCC[5] = scatterIonPos - lx - ly - lz;
neighborIonsBCC[6] = scatterIonPos - lx + ly - lz;
neighborIonsBCC[7] = scatterIonPos - lx + ly + lz;
neighborIonsBCC[8] = scatterIonPos - lx - ly + lz;
neighborIonsBCC[9] = scatterIonPos + lz * 2;
neighborIonsBCC[10] = scatterIonPos - lz * 2;
neighborIonsBCC[11] = scatterIonPos + ly * 2;
neighborIonsBCC[12] = scatterIonPos - ly * 2;
neighborIonsBCC[13] = scatterIonPos - lx * 2;
}
//set DiPrev to Di
DiPrev = Di;
//update current lambda to lambdaPrime
lambda = lambdaPrime;
//now the while condition of the mother do loop checks if the particle has lesser
energy than our lowest energy limit, ef.
}
while(e > ef);
//since we are out of the mother do loop now, the particle must have come to a
stop. So, increase the final particle distributions if the particle has not been
transmitted or backscattered.
if( ((transmitted == 0)) && ((backscattered == 0)) && ((insideChannel == 1)) )
{
ip = (int)(pl/cw + 1.0);
if(ip > 100) ip = 100;
//ipl[ip] = ipl[ip] + 1;
xsum = xsum + Di.x;
//my own bin function
selectedXBin = whichBin(Di.x, xx[Layer], numXBin);
//write the selected bin to the output file
//outStream << selectedXBin << endl;
//cout << x << endl << xx[Layer] << endl << numXBin << endl << selectedXBin;
xBin[selectedXBin] = xBin[selectedXBin] + 1;
//print final x value for plotting histogram
//cout << “ion “ << ih << “ final x: “ << Di.x << endl;
infoStream << “ion “ << ih << “ final x: “ << Di.x << endl;
//cout << Di.x << “,”;
rangeStream << Di.x << endl;
plsum = plsum + pl;
icsum = icsum + ic;
//ipl is the ion path length - the total avg. distance the ion travels
regardless of direction before it comes to stop
}
//that brings us to the end of one ion’s journey, now go to next ion by going back
to the for loop’s beginning..
}
//and this ends the monte carlo loop function. Take care of necessary structures and
variables that need to be cleared/deleted
outStream.close();
scatterStream.close();
infoStream << “Number of Backscattered Ions: “ << ib << endl;
infoStream.close();
rangeStream.close();
}
int whichNonUniformBin(double e, double arr[], int numBins)
{
double low = 0, high = arr[0];
if((e>=low) && (e<high))
return 0;
else
{
for(int i = 0; i < numBins; i++)
{
low += arr[i];
high += arr[i+1];
//cout << “\tlow: “ << low << “, high:” << high << endl;
if((e>=low) && (e<high))
return i;
}
}
}
142
//============================================================================
// Name : monte.cpp
// Author : Nazmus Saquib
// Version :
// Copyright :
// Description : BCA code in C++
//============================================================================
#include “Globals.h”
#include “scoef.h”
#include “rstop.h”
#include “muscle_bca.h”
#include “vectorGeometry.h”
const int numXBin = 100;
const int numIons = 1;
int xBin[numXBin+1] = {0};
int selectedXBin = 0;
double rho[4]={0.0};
int n[]={0,0,0,0};
double e0kev, m1, cw, ed, latticeConst;
int z1, hn, iy, nowout;
double dx[3] = {0.0};
int zt[3][7] = {0};
double mt[3][7] = {0.};
double t[3][7] = {0.};
int Layer; //use this for number of layers rather than the L in the program;
//remember this cannot be set to 0. Other loops/arrays may start from
//0, but keep this >= 1;
//the arrays..
double my[3][7]= {0},
ai[3][7]= {0},
fi[3][7]= {0},
ec[3][7]= {0},
io[3][7]= {0},
k[3]= {0},
kl[3][7]= {0};
double vf[3][7]= {0},
mu[3]= {0},
ioniz[3]= {0},
h[3]= {0},
xx[3]= {0},
m2[3]= {0.0},
z2[3]= {0},
c[3]= {0},
epsbk[3]= {0},
arho[3]= {0};
double a[3]= {0},
f[3]= {0},
lm[3]= {0},
pmax[3]= {0},
fd[3]= {0},
kd[3]= {0},
sbk[3]= {0},
lf[3]= {0},
yy[8]= {0};
double se[3][1000]= {0.0},
seo[1000]= {0.0},
epsdg[3]= {0.0};
double ls = 0., lo = 0., maximum = 0.;
double xsum = 0, x2sum = 0, x3sum = 0, x4sum = 0, plsum = 0, pl2sum = 0;
double avex = 0, vari = 0, sigma = 0, v = 0, v2 = 0, Gamma = 0, beta = 0, y = 0, avepl
= 0, sigpl = 0, avecol = 0;
int i = 0, j = 0;
int ib = 0, it = 0;
double eb = 0.0, et = 0.0;
int icsum = 0;
double y2sum = 0, xy2sum = 0, x2y2su = 0, y4sum = 0;
double tau = 0;
int iii = -1;
//my dummy vars
int w; double q;
//my customized data structures or vars
scoefData scoefz1;
rstopData rstp;
//these vars (continuing from this line) are added later as needed, vars that were not
declared in the initialization of trim85 but showed up in the middle.
double e0, ef;
int iz;
double alfa, alpha;
double tmin, da;
double L0;
int iz1;
double ee;
int izt;
double nh;
double epso;
int ih;
double e;
//boolean for keeping track of a particle being transmitted or backscattered
int transmitted = 0;
int backscattered = 0;
//boolean for keeping track of channeling
int insideChannel = 1;
//boolean for determining whether to scatter from neighbor atoms
int neighborFlag = 0;
//main function
int main()
{
cout << “Initializing” << endl;
Initialize(“IronInput.dat”);
calculateAvgMassOfLayer();
getStoppingForTarget();
setInitialConditions();
MonteCarlo();
/* *********************** Testing Ground for arrays and variables
******************** */
for (w = 1; w <= 8; w++) cout << “\t “ << yy[w];
for (w = 1; w <= 3; w++) cout << “\n\t “ << xx[w];
cout << “CW or L0: “ << L0;
//(trouble! The values of n[] elements are changing like crazy)
cout << endl << n[0] << “\t” << n[1] << “\t” << n[2] << “\t” << n[3] << endl;
cout << endl << rho[0] << “\t” << rho[1] << “\t” << rho[2] << “\t” << rho[3] <<
“\t” << rho[4] << endl;
//test z2[], m2[] arrays
for (w = 1; w <= Layer; w++) cout << “\t “ << z2[w];
for (w = 1; w <= Layer; w++) cout << “\n\t “ << m2[w];
//test the se values
cout << endl << se[1][1000] << “ “ << se[2][1000] << “ “ << se[3][1000] << endl;
//test the se[] values by printing 10th element from the array (to be implemented)
//for (w = 1; w <= 100; w++)
//{
//for (int sss = 1; sss <= 50; sss++)
//{
//cout << “\t” << mpart[w][sss];
//}
//}
/* *********************** End of Testing Ground ************************** */
cout << endl;
//Now print values of each bin in xBin
//for (w = 1; w <= numXBin; w++) cout << xBin[w] << “,”;
//print final x values
cout << endl;
cout << “Number of Backscattered Ions: “ << ib << endl;
cout << “Number of Transmitted Ions: “ << it << endl;
return 0;
}
//end of main
//Helper functions follow from here
//initialize variables and setup each layer over here
void Initialize(char* filename)
{
//Read command file
ifstream instream;
instream.open(filename,ios::in);
cout << filename;
if (!instream)
{
exitOnError(filename);
}
instream >> e0kev >> z1 >> m1 >> latticeConst >> hn >> cw >> ed >> iy >> nowout;
instream >> dx[1] >> rho[1];
instream >> zt[1][1] >> mt[1][1] >> t[1][1];
instream >> n[1];
instream >> dx[2] >> rho[2];
instream >> zt[2][1] >> mt[2][1] >> t[2][1];
instream >> n[2];
instream >> dx[3] >> rho[3];
instream >> zt[3][1] >> mt[3][1] >> t[3][1];
instream >> n[3];
for (w = 0; w <= 3; w++)
{ if (n[w] != 1) n[w] = 1; }
instream.close();
Layer = 3;
//done with primary (crude) setup, off to reading scoef.dat file
iz = z1;
getstructScoef(iz, scoefz1, “scoef1.dat”); //used to get pcoef data yy in trim85
//so we put the values in yy here immediately
for (w = 1; w <= 8; w++)
{ yy[w] = scoefz1.pcoef[w]; }
//note: although yy turns out to be just a dummy array
e0 = e0kev*1000; //convert to ev.
if (ed == 0.) ed = 25.0;
ef = Max(5.0, e0kev*0.1);
//alfa = angle of incidence, alpha = radian of alfa
alfa = 0.;
alpha = alfa*Pi/180;
tmin = 5.0;
tau = 0.0;
da = 3.0;
if (iy == 0) iy = 16381;
//now calculate the total depth of each layer = xx(l), and grid spacing cw
xx[1] = dx[1];
for (w = 2; w <= 3; w++) { xx[w] = dx[w] + xx[w-1]; }
if (cw == 0) cw = 0.01*xx[3];
L0 = cw;
//take care of any custom variable or struct I made
rstp.vfermi = 0.0; //set this to 0. for the time being (see log for explanation)
//now, off to avg mass of layer in the next void function
}
//avg mass and atomic number of each layer
void calculateAvgMassOfLayer()
{
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
h[LL] = h[LL] + t[LL][w];
//cout << “testing here..” << rstp.vfermi << endl;
}
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
t[LL][w] = t[LL][w]/h[LL];
m2[LL] = m2[LL] + t[LL][w] * mt[LL][w];
z2[LL] = z2[LL] + t[LL][w] * zt[LL][w];
//note: z2 wont be an integer once t has a value other than 1.0??
//so are we calculating average atomic number here? why?
}
}
//done with this, off to finding electronic stopping powers in the next function
}
void getStoppingForTarget()
{
iz1 = z1; ee = 0;
for (int LL = 1; LL <= Layer; LL++)
{
arho[LL] = rho[LL] * 0.6022/(m2[LL]);
mu[LL] = m1/(m2[LL]);
int ii = n[LL];
for (int nn = 1; nn <= ii; nn++)
{
//set rstp.se[1..1000] = 0. Clear it for the next loop
for (w = 1; w <= 1000; w++)
{ rstp.se[w] = 0.; }
izt = zt[LL][nn];
//calling getrstop now. units, lfctr, vfermi = 1 (doesnt matter)
getrStop(iz1, izt, e0kev, 1, 1., 1., rstp); //rstp defined in header
//set this anyway, though I dont calculate this in RSTOP
vf[LL][nn] = rstp.vfermi; //which is just set 0 in the struct def.
for (w = 1; w <= 1000; w++)
{
se[LL][w] = se[LL][w] + rstp.se[w] * t[LL][nn] * arho[LL];
}
}
}
//now, off to setting up initial conditions next function
}
void setInitialConditions()
{
nh = hn; //number of histories
for (int LL = 1; LL <= Layer; LL++)
{
a[LL] = 0.5292 * 0.8853 / ( pow(z1, 0.23) + pow(z2[LL], 0.23) );
//now calculate the mean flight path with the conditions given in trim85
f[LL] = a[LL] * m2[LL] / ( z1 * z2[LL] * 14.4 * (m1 + m2[LL] ) );
epso = e0 * f[LL];
epsdg[LL] = tmin * f[LL] * pow( (1.0 + mu[LL]) , 2) / (4.0 * mu[LL]);
fd[LL] = 0.01 * pow( z2[LL], (-7.0/3.0) );
kd[LL] = 0.1334 * pow ( z2[LL], (2.0/3.0) ) / sqrt( m2[LL] );
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
my[LL][w] = m1/mt[LL][w];
ec[LL][w] = 4.0 * my[LL][w] / pow( ( 1.0 + my[LL][w] ), 2);
ai[LL][w] = 0.5292 * 0.8853 / ( pow(z1,0.23) + pow(zt[LL][w],0.23) );
fi[LL][w] = ai[LL][w] * mt[LL][w] / ( z1 * zt[LL][w] * 14.4 * ( m1 + mt[LL][w] ) );
}
}
cout << “Setup finished. Starting Monte Carlo Loops..”;
//off to monte carlo loop in next routine
}
void MonteCarlo()
{
//custom variables and arrays for this section
double e;
double cosin = 0.0, siny = 0.0, sine = 0.0, cosy = 0.0;
double pl = 0.0;
int ic;
int LL = 1;
double eps;
double eeg;
double p;
double b;
int ie, ia; //not sure if ie or ia should be double. They are used to access elements
of the m[][] array at some point
double see;
double dee;
double s2, c2, ct, st;
double r, rr;
double ex1, ex2, ex3, ex4;
double v, v1;
double fr, fr1;
double q;
double roc, sqe;
double cc, aa, ff;
double delta, co;
double den;
double phi, psi;
double x1;
int ip;
//variables for crystal calculations
double sep = 0.0;
int ionCounter = 0;
double p1, p2;
double Theta = 0.0;
double rTheta = 0.0, rPhi = 0.0;
double thetaThreshold = 0.5;
double crystalMuonY = 0.0, crystalMuonZ = 0.0;
//amount of translations in y and z axes
double translationY = 0.0, translationZ = 0.0;
//Scatter Plot variables
const int numScatterPlotBins = 5;
double scatterPlot[numScatterPlotBins + 1] = {0.0};
//Vector declarations
//lattice constant of Target (input from file)
double latticeConstant = latticeConst;
Vector3 ions[4];
Vector3 ionsOrdered[4];
Vector3 neighborIonsBCC[14];
Vector3 neighborIonsFCC[14];
Vector3 ionTranslationY(0,translationY,0);
Vector3 ionTranslationZ(0,0,translationZ);
Vector3 unitzplus, unitzminus, unityplus, unityminus, unitxplus, unitxminus;
unitzplus.z = 1;
unitzminus.z = -1;
unityplus.y = 1;
unityminus.y = -1;
unitxplus.x = 1;
unitxminus.x = -1;
Vector3 initialDirection(1,0,0);
Vector3 d;
d.x = 1;
d *= latticeConstant/2;
Vector3 lx(latticeConstant/2, 0, 0);
Vector3 ly(0, latticeConstant/2, 0);
Vector3 lz(0, 0, latticeConstant/2);
Vector3 lambda;
Vector3 lambdaPrime;
Vector3 pVector;
Vector3 pUnitVector;
Vector3 sepVector;
Vector3 Di;
Vector3 DiPrev;
//Vector3 DiPrevToDi;
Vector3 delX;
Vector3 delX1, delX2;
Vector3 dummy1, dummy2, temp;
Vector3 scatterIonPos;
//initialize the random number generator
srand(time(NULL));
//open file to write output
ofstream outStream;
outStream.open(“coords0.txt”);
if(outStream.fail())
{
exitOnError(“Could not open Output file”);
}
//write basic information in the output file
//number of ions, ion energy, total depth, depth of each layer
outStream << nh << “\t” << e0kev << “\t” << xx[Layer] << “\t” << dx[1] << “\t”
<< dx[2] << “\t” << dx[3] << endl;
//open scatter plot file to write current Y and Z coordinates of muons at designated
intervals
ofstream scatterStream;
scatterStream.open(“scatterOut1.txt”);
if(scatterStream.fail())
{
exitOnError(“Could not open Scatter Plot Output file”);
}
//open range distribution file to write final X coordinates of muons
ofstream rangeStream;
rangeStream.open(“rangeOut1.txt”);
if(rangeStream.fail())
{
exitOnError(“Could not open Range Distribution Output file”);
}
//Open general information dump file
ofstream infoStream;
infoStream.open(“info1.txt”);
if(infoStream.fail())
{
exitOnError(“Could not open general information Output file”);
}
//Entering the target
//First set up for the top layer
for (ih = 1; ih <= nh; ih++)
{
avex = xsum / Max(1.0, (float)(ih - ib - it - 1));
if (talk == 2) cout << “Average ion range so far: “ << avex << “ angstroms.”
<<endl;
if (talk > 2) cout << “Now starting ion number “ << ih << endl;
e = e0;
//set scatterPlot array (the intervals)
scatterPlot[0] = 10;
scatterPlot[1] = 30;
scatterPlot[2] = 50;
scatterPlot[3] = 100;
scatterPlot[4] = 150;
scatterPlot[5] = 200;
/*
for(int ccc = 0; ccc <= numScatterPlotBins; ccc++)
{
cout << “scatter plot “ << ccc << “: “ << scatterPlot[ccc] << endl;
}
*/
//Initial Ion Positions
ions[0] = d + ionTranslationZ + unitzminus * (latticeConstant/2);
ions[1] = d + ionTranslationZ + unitzplus * (latticeConstant/2);
ions[2] = d * 2 + ionTranslationY + unityminus * (latticeConstant/2);
ions[3] = d * 2 + ionTranslationY + unityplus * (latticeConstant/2);
//Create a polygon that resides on the lateral axes.
//The points are put on anticlockwise order, which is important for
//testing whether the test point lies on this polygon
ionsOrdered[0] = ions[0];
ionsOrdered[1] = ions[2];
ionsOrdered[2] = ions[1];
ionsOrdered[3] = ions[3];
//generate random theta and phi angles.
rTheta = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * thetaThreshold;
rPhi = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * 2 * Pi;
//find corresponding x, y and z components of the direction vector.
//radius of the direction vector is 1
initialDirection.x = cos(rTheta);
initialDirection.z = sin(rTheta) * cos(rPhi);
initialDirection.y = sin(rTheta) * sin(rPhi);
//set the counter to 0 for a new ion
ionCounter = 0;
pl = 0.0;
ic = 0;
//set initial DiPrev - the origin
DiPrev.x = 0.0; DiPrev.y = 0.0; DiPrev.z = 0.0;
//set initial lambda, the direction of motion. Normalize it.
lambda.clear();
lambda = initialDirection;
lambda.normalize();
//set initial delX to origin
delX.clear();
//clear the dummy delX vectors, set them to origin
delX1.clear();
delX2.clear();
dummy1.clear();
dummy2.clear();
temp.clear();
LL = 1;
//set transmitted and backscattered to false
transmitted = 0;
backscattered = 0;
//set channeling to true
insideChannel = 1;
neighborFlag = 0;
//write the initial coordinates to the output file
outStream << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << endl << “Initial: “;
//cout << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << “r1 = “ << r1 << endl;
//cycle for each collision until the energy of the particle becomes too low, or
the particle backscatters, or it goes out of the last layer (transmission)
//needs a do while loop here,
//which I will mention as the ‘mother loop’ from now.
do
{
ic = ic + 1;
eps = e * f[LL];
eeg = sqrt(eps*epsdg[LL]);
//pmax[LL] = a[LL] / (eeg + sqrt(eeg) + 0.125 * pow( eeg, 0.1) );
pmax[LL] = sqrt(3) * (latticeConstant / 2) * 0.7;
//Calculate impact parameter and choose the atom to scatter from.
//Do this for ion pairs 0,1 and 2,3.
if (ionCounter == 0)
{
delX1 = ions[0] - DiPrev;
delX2 = ions[1] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[0];
ions[0] = ions[1];
ions[1] = temp;
//cout << “Vertical Ions swapped” << endl;
}
}
if (ionCounter == 2)
{
delX1 = ions[2] - DiPrev;
delX2 = ions[3] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[2];
ions[2] = ions[3];
ions[3] = temp;
//cout << “Horizontal Ions swapped” << endl;
}
}
//now calculate impact parameter
if(neighborFlag == 0)
{
delX = ions[ionCounter] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
else if(neighborFlag == 1)
{
double impact[13] = {0.0};
double radial[13] = {0.0};
double S[13] = {0.0};
double sumS = 0.0;
double Probability[13] = {0.0};
double rnd_candidate = 0.0;
int selected_candidate = -1;
for(int ncount = 0; ncount <= 13; ncount++)
{
delX = neighborIonsBCC[ncount] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
//scatterIonPos = neighborIonsBCC[ncount];
impact[ncount] = p;
radial[ncount] = delX.magnitude();
S[ncount] = 1 / ( pow(impact[ncount],2) * radial[ncount] );
sumS += S[ncount];
//general scheme of selecting the neighbor ion
// if(p < pmax[LL])
// {
// scatterIonPos = neighborIonsBCC[ncount];
// //cout << “Neighbor “ << ncount << “ is selected” << endl;
// break;
// }
}
for(int ncount = 0; ncount <= 13; ncount++)
{
Probability[ncount] = S[ncount] / sumS;
}
//print out the probability array
cout << endl;
for(int ncount = 0; ncount <= 13; ncount++)
{
//cout << Probability[ncount] << “ “;
infoStream << Probability[ncount] << “ “;
}
infoStream << endl;
//cout << endl;
//random number between 0 and 1
rnd_candidate = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) );
//cout << “rand_candidate: “ << rnd_candidate << endl;
//choose the candidate for scattering
selected_candidate = whichNonUniformBin(rnd_candidate, Probability, 13);
//cout << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate <<
endl;
infoStream << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate
<< endl;
//assign the scatterIonPos variable to the selected neighbor
scatterIonPos = neighborIonsBCC[selected_candidate];
//cout << “Scattering Ion Position: “; scatterIonPos.printVector();
//find the essential quantities for the selected neighbor
delX = neighborIonsBCC[selected_candidate] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
//find eps and b using fi[LL][nn], using nn that I was supposed to find from above
//here im deliberately using nn = 1
eps = fi[LL][1] * e;
b = p / ai[LL][1];
if (eps > 10) //rutherford scattering
{
s2 = 1.0 / (1.0 + (1.0 + b * (1.0 + b)) * pow((2.0 * eps * b), 2) );
c2 = 1.0 - s2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
else //magic formula
{
r = b;
rr = -2.7 * log(eps * b);
if (rr >= b)//note >= sign instead < in trim85
{
rr = -2.7 * log(eps * rr);
if (rr >= b)//note >= sign instead < in trim85
{
r = rr;
}
}
//do while loop that replaces line 330 loop
do
{
ex1 = 0.18175 * exp(-3.1998 * r);
ex2 = 0.50986 * exp(-0.94229 * r);
ex3 = 0.28022 * exp(-0.4029 * r);
ex4 = 0.028171 * exp(-0.20162 * r);
v = (ex1 + ex2 + ex3 + ex4) / r;
v1 = -(v + 3.1998 * ex1 + 0.94229 * ex2 + 0.4029 * ex3 + 0.20162 * ex4) / r;
fr = b * b / r + v * r / eps - r;
fr1 = -b * b / (r * r) + (v + v1 * r) / eps - 1.0;
q = fr / fr1;
r = r - q;
}
while( (Abs(q / r)) > 0.001 );
roc = -2.0 * (eps - v) / v1;
sqe = sqrt(eps);
//5 parameter magic scattering calculation
//below is for universal potential
cc = (0.011615 + sqe) / (0.0071222 + sqe);
aa = 2.0 * eps * (1.0 + (0.99229 / sqe) ) * ( pow(b, cc) );
ff = ( sqrt(aa * aa + 1.0) - aa) * ( (9.3066 + eps) / (14.813 + eps) );
delta = (r - b) * aa * ff / (ff + 1.0);
co = (b + delta + roc) / (r + roc);
c2 = co * co;
s2 = 1.0 - c2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
Theta = acos(ct);
//we are done finding theta (in CM system). So calculate all other quantities.
//find separation and the separation vector.
phi = (Pi - Theta) / 2;
sep = p / tan(phi);
sepVector = lambda * sep;
//find theta in laboratory frame - psi
psi = atan(st / (ct + my[LL][1] ) );
//note: change my[LL][1] to my[LL][nn] when the above section is fixed.
if (psi < 0 ) psi = psi + Pi; //should I do this for crystals?
//find Di, the scattering point vector
Di = DiPrev + delX + pVector - sepVector;
//find new direction of motion
lambdaPrime = lambda * cos(psi) + pUnitVector * sin(psi);
lambdaPrime.normalize();
//find length of step, ls = distance of Di from DiPrev
ls = Di.getDistance(DiPrev);
//find energy lost due to electronic stopping, dee
ie = (int)(e/e0kev+0.5); //should it be 0.5? or less so that ie <=1000?
see = se[LL][ie];
if (e < e0kev) see = se[LL][1] * sqrt(e/e0kev);
dee = ls * see;
// den = energy transferred to recoil
den = ec[LL][1] * s2 * e; //note: I am using ec[LL][1] here instead of [LL][nn].
//cout << “den = “ << den << “, dee = “ << dee << endl;
infoStream << “den = “ << den << “, dee = “ << dee << endl;
e = e - den - dee;
//cout << endl<< “current ion energy: “ << e << endl;
if (dee > maximum) maximum = dee;
pl = pl + ls - tau;
//write the ion position to output file
outStream << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
if((ic%30)==0)
{
//cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
}
//determine which scatter plot Di’s x value belongs to.
//output the y and z coordinates to scatter plot file accordingly.
for(int cc = 0; cc <= numScatterPlotBins; cc++)
{
if( Di.x >= (scatterPlot[cc]) )
{
crystalMuonY = Di.y - translationY;
crystalMuonZ = Di.z - translationZ;
//cout << “scatter plot “ << ct << “: “ << scatterPlot[ct] << endl;
scatterStream << scatterPlot[cc] << “\t” << crystalMuonY << “\t” <<
crystalMuonZ << endl;
//set scatterPlot[ss] to a big number
scatterPlot[cc] = 10000;
//break out of this for loop
break;
}
}
//determine if Di is in the channeling region.
//insideChannel = Di.isInsidePolygon(ionsOrdered, 4);
//break out of parent loop if not inside the channel
if(insideChannel == 0)
{
cout << “Ion “ << ih << “ is out of Channel” << endl;
cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
break;
}
//determine which layer the next collision will be in
if (Di.x < 0.0) //particle is backscattered
{
backscattered = 1; //cout << “ion number “ << ih << “ backscattered.” << endl;
infoStream << “ion number “ << ih << “ backscattered.” << endl;
ib = ib + 1;
eb = eb + e;
break; //break out of ‘mother do loop’ and continue with the next session of
for loop.
}
//here we set the current or next layer the particle will be in
for (w = 1; w <= Layer; w++)
{
if ( (Di.x <= xx[w]) && (w == 1) )
{
LL = 1;
//cout << endl<<”ion is in layer “ << LL << endl;
break;
//break out of this For loop and go check if the particle is transmitted.
}
else if ( (Di.x <= xx[w]) && (Di.x > xx[w-1]) )
{
LL = w;
//cout << “ion is in layer “ << LL <<endl;
break; //break out of this For loop and go check if the particle is
transmitted.
}
}
//now, check for particle transmission, i.e. whether the particle went out of the
last layer.
if(Di.x >= xx[Layer])
{
//particle is transmitted, take care of appropriate variables and break
transmitted = 1;//cout << “ion number “ << ih << “ transmitted.” << endl;
it = it + 1;
et = et + e;
ia = 57.295779 * acos(cosin) / da + 1.0;
ie = 100 * e / e0 + 1.0;
//m[ie][ia] = m[ie][ia] + 1;//note: how is this possible? ie and ia should be
integers in order to access the elements of the array m[][]. But we calculate them as
doubles here!
break; //break out of the ‘mother’ do loop
}
//now take care of ionCounter and other variables for the next scattering
if(neighborFlag == 0)
{
if(ionCounter == 3)
{
//ionCounter = 0;
neighborFlag = 1;
scatterIonPos = ions[3];
//cout << endl << “got out of first two layers” << endl;
}
else
{
ionCounter++;
}
}
if(neighborFlag == 1)
{
//cout << “Updating Neighbor Ions” << endl;
neighborIonsBCC[0] = scatterIonPos + lx - ly + lz;
neighborIonsBCC[1] = scatterIonPos + lx + ly + lz;
neighborIonsBCC[2] = scatterIonPos + lx + ly - lz;
neighborIonsBCC[3] = scatterIonPos + lx - ly - lz;
neighborIonsBCC[4] = scatterIonPos + lx * 2;
neighborIonsBCC[5] = scatterIonPos - lx - ly - lz;
neighborIonsBCC[6] = scatterIonPos - lx + ly - lz;
neighborIonsBCC[7] = scatterIonPos - lx + ly + lz;
neighborIonsBCC[8] = scatterIonPos - lx - ly + lz;
neighborIonsBCC[9] = scatterIonPos + lz * 2;
neighborIonsBCC[10] = scatterIonPos - lz * 2;
neighborIonsBCC[11] = scatterIonPos + ly * 2;
neighborIonsBCC[12] = scatterIonPos - ly * 2;
neighborIonsBCC[13] = scatterIonPos - lx * 2;
}
//set DiPrev to Di
DiPrev = Di;
//update current lambda to lambdaPrime
lambda = lambdaPrime;
//now the while condition of the mother do loop checks if the particle has lesser
energy than our lowest energy limit, ef.
}
while(e > ef);
//since we are out of the mother do loop now, the particle must have come to a
stop. So, increase the final particle distributions if the particle has not been
transmitted or backscattered.
if( ((transmitted == 0)) && ((backscattered == 0)) && ((insideChannel == 1)) )
{
ip = (int)(pl/cw + 1.0);
if(ip > 100) ip = 100;
//ipl[ip] = ipl[ip] + 1;
xsum = xsum + Di.x;
//my own bin function
selectedXBin = whichBin(Di.x, xx[Layer], numXBin);
//write the selected bin to the output file
//outStream << selectedXBin << endl;
//cout << x << endl << xx[Layer] << endl << numXBin << endl << selectedXBin;
xBin[selectedXBin] = xBin[selectedXBin] + 1;
//print final x value for plotting histogram
//cout << “ion “ << ih << “ final x: “ << Di.x << endl;
infoStream << “ion “ << ih << “ final x: “ << Di.x << endl;
//cout << Di.x << “,”;
rangeStream << Di.x << endl;
plsum = plsum + pl;
icsum = icsum + ic;
//ipl is the ion path length - the total avg. distance the ion travels
regardless of direction before it comes to stop
}
//that brings us to the end of one ion’s journey, now go to next ion by going back
to the for loop’s beginning..
}
//and this ends the monte carlo loop function. Take care of necessary structures and
variables that need to be cleared/deleted
outStream.close();
scatterStream.close();
infoStream << “Number of Backscattered Ions: “ << ib << endl;
infoStream.close();
rangeStream.close();
}
int whichNonUniformBin(double e, double arr[], int numBins)
{
double low = 0, high = arr[0];
if((e>=low) && (e<high))
return 0;
else
{
for(int i = 0; i < numBins; i++)
{
low += arr[i];
high += arr[i+1];
//cout << “\tlow: “ << low << “, high:” << high << endl;
if((e>=low) && (e<high))
return i;
}
}
}
143
//============================================================================
// Name : monte.cpp
// Author : Nazmus Saquib
// Version :
// Copyright :
// Description : BCA code in C++
//============================================================================
#include “Globals.h”
#include “scoef.h”
#include “rstop.h”
#include “muscle_bca.h”
#include “vectorGeometry.h”
const int numXBin = 100;
const int numIons = 1;
int xBin[numXBin+1] = {0};
int selectedXBin = 0;
double rho[4]={0.0};
int n[]={0,0,0,0};
double e0kev, m1, cw, ed, latticeConst;
int z1, hn, iy, nowout;
double dx[3] = {0.0};
int zt[3][7] = {0};
double mt[3][7] = {0.};
double t[3][7] = {0.};
int Layer; //use this for number of layers rather than the L in the program;
//remember this cannot be set to 0. Other loops/arrays may start from
//0, but keep this >= 1;
//the arrays..
double my[3][7]= {0},
ai[3][7]= {0},
fi[3][7]= {0},
ec[3][7]= {0},
io[3][7]= {0},
k[3]= {0},
kl[3][7]= {0};
double vf[3][7]= {0},
mu[3]= {0},
ioniz[3]= {0},
h[3]= {0},
xx[3]= {0},
m2[3]= {0.0},
z2[3]= {0},
c[3]= {0},
epsbk[3]= {0},
arho[3]= {0};
double a[3]= {0},
f[3]= {0},
lm[3]= {0},
pmax[3]= {0},
fd[3]= {0},
kd[3]= {0},
sbk[3]= {0},
lf[3]= {0},
yy[8]= {0};
double se[3][1000]= {0.0},
seo[1000]= {0.0},
epsdg[3]= {0.0};
double ls = 0., lo = 0., maximum = 0.;
double xsum = 0, x2sum = 0, x3sum = 0, x4sum = 0, plsum = 0, pl2sum = 0;
double avex = 0, vari = 0, sigma = 0, v = 0, v2 = 0, Gamma = 0, beta = 0, y = 0, avepl
= 0, sigpl = 0, avecol = 0;
int i = 0, j = 0;
int ib = 0, it = 0;
double eb = 0.0, et = 0.0;
int icsum = 0;
double y2sum = 0, xy2sum = 0, x2y2su = 0, y4sum = 0;
double tau = 0;
int iii = -1;
//my dummy vars
int w; double q;
//my customized data structures or vars
scoefData scoefz1;
rstopData rstp;
//these vars (continuing from this line) are added later as needed, vars that were not
declared in the initialization of trim85 but showed up in the middle.
double e0, ef;
int iz;
double alfa, alpha;
double tmin, da;
double L0;
int iz1;
double ee;
int izt;
double nh;
double epso;
int ih;
double e;
//boolean for keeping track of a particle being transmitted or backscattered
int transmitted = 0;
int backscattered = 0;
//boolean for keeping track of channeling
int insideChannel = 1;
//boolean for determining whether to scatter from neighbor atoms
int neighborFlag = 0;
//main function
int main()
{
cout << “Initializing” << endl;
Initialize(“IronInput.dat”);
calculateAvgMassOfLayer();
getStoppingForTarget();
setInitialConditions();
MonteCarlo();
/* *********************** Testing Ground for arrays and variables
******************** */
for (w = 1; w <= 8; w++) cout << “\t “ << yy[w];
for (w = 1; w <= 3; w++) cout << “\n\t “ << xx[w];
cout << “CW or L0: “ << L0;
//(trouble! The values of n[] elements are changing like crazy)
cout << endl << n[0] << “\t” << n[1] << “\t” << n[2] << “\t” << n[3] << endl;
cout << endl << rho[0] << “\t” << rho[1] << “\t” << rho[2] << “\t” << rho[3] <<
“\t” << rho[4] << endl;
//test z2[], m2[] arrays
for (w = 1; w <= Layer; w++) cout << “\t “ << z2[w];
for (w = 1; w <= Layer; w++) cout << “\n\t “ << m2[w];
//test the se values
cout << endl << se[1][1000] << “ “ << se[2][1000] << “ “ << se[3][1000] << endl;
//test the se[] values by printing 10th element from the array (to be implemented)
//for (w = 1; w <= 100; w++)
//{
//for (int sss = 1; sss <= 50; sss++)
//{
//cout << “\t” << mpart[w][sss];
//}
//}
/* *********************** End of Testing Ground ************************** */
cout << endl;
//Now print values of each bin in xBin
//for (w = 1; w <= numXBin; w++) cout << xBin[w] << “,”;
//print final x values
cout << endl;
cout << “Number of Backscattered Ions: “ << ib << endl;
cout << “Number of Transmitted Ions: “ << it << endl;
return 0;
}
//end of main
//Helper functions follow from here
//initialize variables and setup each layer over here
void Initialize(char* filename)
{
//Read command file
ifstream instream;
instream.open(filename,ios::in);
cout << filename;
if (!instream)
{
exitOnError(filename);
}
instream >> e0kev >> z1 >> m1 >> latticeConst >> hn >> cw >> ed >> iy >> nowout;
instream >> dx[1] >> rho[1];
instream >> zt[1][1] >> mt[1][1] >> t[1][1];
instream >> n[1];
instream >> dx[2] >> rho[2];
instream >> zt[2][1] >> mt[2][1] >> t[2][1];
instream >> n[2];
instream >> dx[3] >> rho[3];
instream >> zt[3][1] >> mt[3][1] >> t[3][1];
instream >> n[3];
for (w = 0; w <= 3; w++)
{ if (n[w] != 1) n[w] = 1; }
instream.close();
Layer = 3;
//done with primary (crude) setup, off to reading scoef.dat file
iz = z1;
getstructScoef(iz, scoefz1, “scoef1.dat”); //used to get pcoef data yy in trim85
//so we put the values in yy here immediately
for (w = 1; w <= 8; w++)
{ yy[w] = scoefz1.pcoef[w]; }
//note: although yy turns out to be just a dummy array
e0 = e0kev*1000; //convert to ev.
if (ed == 0.) ed = 25.0;
ef = Max(5.0, e0kev*0.1);
//alfa = angle of incidence, alpha = radian of alfa
alfa = 0.;
alpha = alfa*Pi/180;
tmin = 5.0;
tau = 0.0;
da = 3.0;
if (iy == 0) iy = 16381;
//now calculate the total depth of each layer = xx(l), and grid spacing cw
xx[1] = dx[1];
for (w = 2; w <= 3; w++) { xx[w] = dx[w] + xx[w-1]; }
if (cw == 0) cw = 0.01*xx[3];
L0 = cw;
//take care of any custom variable or struct I made
rstp.vfermi = 0.0; //set this to 0. for the time being (see log for explanation)
//now, off to avg mass of layer in the next void function
}
//avg mass and atomic number of each layer
void calculateAvgMassOfLayer()
{
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
h[LL] = h[LL] + t[LL][w];
//cout << “testing here..” << rstp.vfermi << endl;
}
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
t[LL][w] = t[LL][w]/h[LL];
m2[LL] = m2[LL] + t[LL][w] * mt[LL][w];
z2[LL] = z2[LL] + t[LL][w] * zt[LL][w];
//note: z2 wont be an integer once t has a value other than 1.0??
//so are we calculating average atomic number here? why?
}
}
//done with this, off to finding electronic stopping powers in the next function
}
void getStoppingForTarget()
{
iz1 = z1; ee = 0;
for (int LL = 1; LL <= Layer; LL++)
{
arho[LL] = rho[LL] * 0.6022/(m2[LL]);
mu[LL] = m1/(m2[LL]);
int ii = n[LL];
for (int nn = 1; nn <= ii; nn++)
{
//set rstp.se[1..1000] = 0. Clear it for the next loop
for (w = 1; w <= 1000; w++)
{ rstp.se[w] = 0.; }
izt = zt[LL][nn];
//calling getrstop now. units, lfctr, vfermi = 1 (doesnt matter)
getrStop(iz1, izt, e0kev, 1, 1., 1., rstp); //rstp defined in header
//set this anyway, though I dont calculate this in RSTOP
vf[LL][nn] = rstp.vfermi; //which is just set 0 in the struct def.
for (w = 1; w <= 1000; w++)
{
se[LL][w] = se[LL][w] + rstp.se[w] * t[LL][nn] * arho[LL];
}
}
}
//now, off to setting up initial conditions next function
}
void setInitialConditions()
{
nh = hn; //number of histories
for (int LL = 1; LL <= Layer; LL++)
{
a[LL] = 0.5292 * 0.8853 / ( pow(z1, 0.23) + pow(z2[LL], 0.23) );
//now calculate the mean flight path with the conditions given in trim85
f[LL] = a[LL] * m2[LL] / ( z1 * z2[LL] * 14.4 * (m1 + m2[LL] ) );
epso = e0 * f[LL];
epsdg[LL] = tmin * f[LL] * pow( (1.0 + mu[LL]) , 2) / (4.0 * mu[LL]);
fd[LL] = 0.01 * pow( z2[LL], (-7.0/3.0) );
kd[LL] = 0.1334 * pow ( z2[LL], (2.0/3.0) ) / sqrt( m2[LL] );
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
my[LL][w] = m1/mt[LL][w];
ec[LL][w] = 4.0 * my[LL][w] / pow( ( 1.0 + my[LL][w] ), 2);
ai[LL][w] = 0.5292 * 0.8853 / ( pow(z1,0.23) + pow(zt[LL][w],0.23) );
fi[LL][w] = ai[LL][w] * mt[LL][w] / ( z1 * zt[LL][w] * 14.4 * ( m1 + mt[LL][w] ) );
}
}
cout << “Setup finished. Starting Monte Carlo Loops..”;
//off to monte carlo loop in next routine
}
void MonteCarlo()
{
//custom variables and arrays for this section
double e;
double cosin = 0.0, siny = 0.0, sine = 0.0, cosy = 0.0;
double pl = 0.0;
int ic;
int LL = 1;
double eps;
double eeg;
double p;
double b;
int ie, ia; //not sure if ie or ia should be double. They are used to access elements
of the m[][] array at some point
double see;
double dee;
double s2, c2, ct, st;
double r, rr;
double ex1, ex2, ex3, ex4;
double v, v1;
double fr, fr1;
double q;
double roc, sqe;
double cc, aa, ff;
double delta, co;
double den;
double phi, psi;
double x1;
int ip;
//variables for crystal calculations
double sep = 0.0;
int ionCounter = 0;
double p1, p2;
double Theta = 0.0;
double rTheta = 0.0, rPhi = 0.0;
double thetaThreshold = 0.5;
double crystalMuonY = 0.0, crystalMuonZ = 0.0;
//amount of translations in y and z axes
double translationY = 0.0, translationZ = 0.0;
//Scatter Plot variables
const int numScatterPlotBins = 5;
double scatterPlot[numScatterPlotBins + 1] = {0.0};
//Vector declarations
//lattice constant of Target (input from file)
double latticeConstant = latticeConst;
Vector3 ions[4];
Vector3 ionsOrdered[4];
Vector3 neighborIonsBCC[14];
Vector3 neighborIonsFCC[14];
Vector3 ionTranslationY(0,translationY,0);
Vector3 ionTranslationZ(0,0,translationZ);
Vector3 unitzplus, unitzminus, unityplus, unityminus, unitxplus, unitxminus;
unitzplus.z = 1;
unitzminus.z = -1;
unityplus.y = 1;
unityminus.y = -1;
unitxplus.x = 1;
unitxminus.x = -1;
Vector3 initialDirection(1,0,0);
Vector3 d;
d.x = 1;
d *= latticeConstant/2;
Vector3 lx(latticeConstant/2, 0, 0);
Vector3 ly(0, latticeConstant/2, 0);
Vector3 lz(0, 0, latticeConstant/2);
Vector3 lambda;
Vector3 lambdaPrime;
Vector3 pVector;
Vector3 pUnitVector;
Vector3 sepVector;
Vector3 Di;
Vector3 DiPrev;
//Vector3 DiPrevToDi;
Vector3 delX;
Vector3 delX1, delX2;
Vector3 dummy1, dummy2, temp;
Vector3 scatterIonPos;
//initialize the random number generator
srand(time(NULL));
//open file to write output
ofstream outStream;
outStream.open(“coords0.txt”);
if(outStream.fail())
{
exitOnError(“Could not open Output file”);
}
//write basic information in the output file
//number of ions, ion energy, total depth, depth of each layer
outStream << nh << “\t” << e0kev << “\t” << xx[Layer] << “\t” << dx[1] << “\t”
<< dx[2] << “\t” << dx[3] << endl;
//open scatter plot file to write current Y and Z coordinates of muons at designated
intervals
ofstream scatterStream;
scatterStream.open(“scatterOut1.txt”);
if(scatterStream.fail())
{
exitOnError(“Could not open Scatter Plot Output file”);
}
//open range distribution file to write final X coordinates of muons
ofstream rangeStream;
rangeStream.open(“rangeOut1.txt”);
if(rangeStream.fail())
{
exitOnError(“Could not open Range Distribution Output file”);
}
//Open general information dump file
ofstream infoStream;
infoStream.open(“info1.txt”);
if(infoStream.fail())
{
exitOnError(“Could not open general information Output file”);
}
//Entering the target
//First set up for the top layer
for (ih = 1; ih <= nh; ih++)
{
avex = xsum / Max(1.0, (float)(ih - ib - it - 1));
if (talk == 2) cout << “Average ion range so far: “ << avex << “ angstroms.”
<<endl;
if (talk > 2) cout << “Now starting ion number “ << ih << endl;
e = e0;
//set scatterPlot array (the intervals)
scatterPlot[0] = 10;
scatterPlot[1] = 30;
scatterPlot[2] = 50;
scatterPlot[3] = 100;
scatterPlot[4] = 150;
scatterPlot[5] = 200;
/*
for(int ccc = 0; ccc <= numScatterPlotBins; ccc++)
{
cout << “scatter plot “ << ccc << “: “ << scatterPlot[ccc] << endl;
}
*/
//Initial Ion Positions
ions[0] = d + ionTranslationZ + unitzminus * (latticeConstant/2);
ions[1] = d + ionTranslationZ + unitzplus * (latticeConstant/2);
ions[2] = d * 2 + ionTranslationY + unityminus * (latticeConstant/2);
ions[3] = d * 2 + ionTranslationY + unityplus * (latticeConstant/2);
//Create a polygon that resides on the lateral axes.
//The points are put on anticlockwise order, which is important for
//testing whether the test point lies on this polygon
ionsOrdered[0] = ions[0];
ionsOrdered[1] = ions[2];
ionsOrdered[2] = ions[1];
ionsOrdered[3] = ions[3];
//generate random theta and phi angles.
rTheta = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * thetaThreshold;
rPhi = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * 2 * Pi;
//find corresponding x, y and z components of the direction vector.
//radius of the direction vector is 1
initialDirection.x = cos(rTheta);
initialDirection.z = sin(rTheta) * cos(rPhi);
initialDirection.y = sin(rTheta) * sin(rPhi);
//set the counter to 0 for a new ion
ionCounter = 0;
pl = 0.0;
ic = 0;
//set initial DiPrev - the origin
DiPrev.x = 0.0; DiPrev.y = 0.0; DiPrev.z = 0.0;
//set initial lambda, the direction of motion. Normalize it.
lambda.clear();
lambda = initialDirection;
lambda.normalize();
//set initial delX to origin
delX.clear();
//clear the dummy delX vectors, set them to origin
delX1.clear();
delX2.clear();
dummy1.clear();
dummy2.clear();
temp.clear();
LL = 1;
//set transmitted and backscattered to false
transmitted = 0;
backscattered = 0;
//set channeling to true
insideChannel = 1;
neighborFlag = 0;
//write the initial coordinates to the output file
outStream << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << endl << “Initial: “;
//cout << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << “r1 = “ << r1 << endl;
//cycle for each collision until the energy of the particle becomes too low, or
the particle backscatters, or it goes out of the last layer (transmission)
//needs a do while loop here,
//which I will mention as the ‘mother loop’ from now.
do
{
ic = ic + 1;
eps = e * f[LL];
eeg = sqrt(eps*epsdg[LL]);
//pmax[LL] = a[LL] / (eeg + sqrt(eeg) + 0.125 * pow( eeg, 0.1) );
pmax[LL] = sqrt(3) * (latticeConstant / 2) * 0.7;
//Calculate impact parameter and choose the atom to scatter from.
//Do this for ion pairs 0,1 and 2,3.
if (ionCounter == 0)
{
delX1 = ions[0] - DiPrev;
delX2 = ions[1] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[0];
ions[0] = ions[1];
ions[1] = temp;
//cout << “Vertical Ions swapped” << endl;
}
}
if (ionCounter == 2)
{
delX1 = ions[2] - DiPrev;
delX2 = ions[3] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[2];
ions[2] = ions[3];
ions[3] = temp;
//cout << “Horizontal Ions swapped” << endl;
}
}
//now calculate impact parameter
if(neighborFlag == 0)
{
delX = ions[ionCounter] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
else if(neighborFlag == 1)
{
double impact[13] = {0.0};
double radial[13] = {0.0};
double S[13] = {0.0};
double sumS = 0.0;
double Probability[13] = {0.0};
double rnd_candidate = 0.0;
int selected_candidate = -1;
for(int ncount = 0; ncount <= 13; ncount++)
{
delX = neighborIonsBCC[ncount] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
//scatterIonPos = neighborIonsBCC[ncount];
impact[ncount] = p;
radial[ncount] = delX.magnitude();
S[ncount] = 1 / ( pow(impact[ncount],2) * radial[ncount] );
sumS += S[ncount];
//general scheme of selecting the neighbor ion
// if(p < pmax[LL])
// {
// scatterIonPos = neighborIonsBCC[ncount];
// //cout << “Neighbor “ << ncount << “ is selected” << endl;
// break;
// }
}
for(int ncount = 0; ncount <= 13; ncount++)
{
Probability[ncount] = S[ncount] / sumS;
}
//print out the probability array
cout << endl;
for(int ncount = 0; ncount <= 13; ncount++)
{
//cout << Probability[ncount] << “ “;
infoStream << Probability[ncount] << “ “;
}
infoStream << endl;
//cout << endl;
//random number between 0 and 1
rnd_candidate = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) );
//cout << “rand_candidate: “ << rnd_candidate << endl;
//choose the candidate for scattering
selected_candidate = whichNonUniformBin(rnd_candidate, Probability, 13);
//cout << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate <<
endl;
infoStream << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate
<< endl;
//assign the scatterIonPos variable to the selected neighbor
scatterIonPos = neighborIonsBCC[selected_candidate];
//cout << “Scattering Ion Position: “; scatterIonPos.printVector();
//find the essential quantities for the selected neighbor
delX = neighborIonsBCC[selected_candidate] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
//find eps and b using fi[LL][nn], using nn that I was supposed to find from above
//here im deliberately using nn = 1
eps = fi[LL][1] * e;
b = p / ai[LL][1];
if (eps > 10) //rutherford scattering
{
s2 = 1.0 / (1.0 + (1.0 + b * (1.0 + b)) * pow((2.0 * eps * b), 2) );
c2 = 1.0 - s2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
else //magic formula
{
r = b;
rr = -2.7 * log(eps * b);
if (rr >= b)//note >= sign instead < in trim85
{
rr = -2.7 * log(eps * rr);
if (rr >= b)//note >= sign instead < in trim85
{
r = rr;
}
}
//do while loop that replaces line 330 loop
do
{
ex1 = 0.18175 * exp(-3.1998 * r);
ex2 = 0.50986 * exp(-0.94229 * r);
ex3 = 0.28022 * exp(-0.4029 * r);
ex4 = 0.028171 * exp(-0.20162 * r);
v = (ex1 + ex2 + ex3 + ex4) / r;
v1 = -(v + 3.1998 * ex1 + 0.94229 * ex2 + 0.4029 * ex3 + 0.20162 * ex4) / r;
fr = b * b / r + v * r / eps - r;
fr1 = -b * b / (r * r) + (v + v1 * r) / eps - 1.0;
q = fr / fr1;
r = r - q;
}
while( (Abs(q / r)) > 0.001 );
roc = -2.0 * (eps - v) / v1;
sqe = sqrt(eps);
//5 parameter magic scattering calculation
//below is for universal potential
cc = (0.011615 + sqe) / (0.0071222 + sqe);
aa = 2.0 * eps * (1.0 + (0.99229 / sqe) ) * ( pow(b, cc) );
ff = ( sqrt(aa * aa + 1.0) - aa) * ( (9.3066 + eps) / (14.813 + eps) );
delta = (r - b) * aa * ff / (ff + 1.0);
co = (b + delta + roc) / (r + roc);
c2 = co * co;
s2 = 1.0 - c2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
Theta = acos(ct);
//we are done finding theta (in CM system). So calculate all other quantities.
//find separation and the separation vector.
phi = (Pi - Theta) / 2;
sep = p / tan(phi);
sepVector = lambda * sep;
//find theta in laboratory frame - psi
psi = atan(st / (ct + my[LL][1] ) );
//note: change my[LL][1] to my[LL][nn] when the above section is fixed.
if (psi < 0 ) psi = psi + Pi; //should I do this for crystals?
//find Di, the scattering point vector
Di = DiPrev + delX + pVector - sepVector;
//find new direction of motion
lambdaPrime = lambda * cos(psi) + pUnitVector * sin(psi);
lambdaPrime.normalize();
//find length of step, ls = distance of Di from DiPrev
ls = Di.getDistance(DiPrev);
//find energy lost due to electronic stopping, dee
ie = (int)(e/e0kev+0.5); //should it be 0.5? or less so that ie <=1000?
see = se[LL][ie];
if (e < e0kev) see = se[LL][1] * sqrt(e/e0kev);
dee = ls * see;
// den = energy transferred to recoil
den = ec[LL][1] * s2 * e; //note: I am using ec[LL][1] here instead of [LL][nn].
//cout << “den = “ << den << “, dee = “ << dee << endl;
infoStream << “den = “ << den << “, dee = “ << dee << endl;
e = e - den - dee;
//cout << endl<< “current ion energy: “ << e << endl;
if (dee > maximum) maximum = dee;
pl = pl + ls - tau;
//write the ion position to output file
outStream << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
if((ic%30)==0)
{
//cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
}
//determine which scatter plot Di’s x value belongs to.
//output the y and z coordinates to scatter plot file accordingly.
for(int cc = 0; cc <= numScatterPlotBins; cc++)
{
if( Di.x >= (scatterPlot[cc]) )
{
crystalMuonY = Di.y - translationY;
crystalMuonZ = Di.z - translationZ;
//cout << “scatter plot “ << ct << “: “ << scatterPlot[ct] << endl;
scatterStream << scatterPlot[cc] << “\t” << crystalMuonY << “\t” <<
crystalMuonZ << endl;
//set scatterPlot[ss] to a big number
scatterPlot[cc] = 10000;
//break out of this for loop
break;
}
}
//determine if Di is in the channeling region.
//insideChannel = Di.isInsidePolygon(ionsOrdered, 4);
//break out of parent loop if not inside the channel
if(insideChannel == 0)
{
cout << “Ion “ << ih << “ is out of Channel” << endl;
cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
break;
}
//determine which layer the next collision will be in
if (Di.x < 0.0) //particle is backscattered
{
backscattered = 1; //cout << “ion number “ << ih << “ backscattered.” << endl;
infoStream << “ion number “ << ih << “ backscattered.” << endl;
ib = ib + 1;
eb = eb + e;
break; //break out of ‘mother do loop’ and continue with the next session of
for loop.
}
//here we set the current or next layer the particle will be in
for (w = 1; w <= Layer; w++)
{
if ( (Di.x <= xx[w]) && (w == 1) )
{
LL = 1;
//cout << endl<<”ion is in layer “ << LL << endl;
break;
//break out of this For loop and go check if the particle is transmitted.
}
else if ( (Di.x <= xx[w]) && (Di.x > xx[w-1]) )
{
LL = w;
//cout << “ion is in layer “ << LL <<endl;
break; //break out of this For loop and go check if the particle is
transmitted.
}
}
//now, check for particle transmission, i.e. whether the particle went out of the
last layer.
if(Di.x >= xx[Layer])
{
//particle is transmitted, take care of appropriate variables and break
transmitted = 1;//cout << “ion number “ << ih << “ transmitted.” << endl;
it = it + 1;
et = et + e;
ia = 57.295779 * acos(cosin) / da + 1.0;
ie = 100 * e / e0 + 1.0;
//m[ie][ia] = m[ie][ia] + 1;//note: how is this possible? ie and ia should be
integers in order to access the elements of the array m[][]. But we calculate them as
doubles here!
break; //break out of the ‘mother’ do loop
}
//now take care of ionCounter and other variables for the next scattering
if(neighborFlag == 0)
{
if(ionCounter == 3)
{
//ionCounter = 0;
neighborFlag = 1;
scatterIonPos = ions[3];
//cout << endl << “got out of first two layers” << endl;
}
else
{
ionCounter++;
}
}
if(neighborFlag == 1)
{
//cout << “Updating Neighbor Ions” << endl;
neighborIonsBCC[0] = scatterIonPos + lx - ly + lz;
neighborIonsBCC[1] = scatterIonPos + lx + ly + lz;
neighborIonsBCC[2] = scatterIonPos + lx + ly - lz;
neighborIonsBCC[3] = scatterIonPos + lx - ly - lz;
neighborIonsBCC[4] = scatterIonPos + lx * 2;
neighborIonsBCC[5] = scatterIonPos - lx - ly - lz;
neighborIonsBCC[6] = scatterIonPos - lx + ly - lz;
neighborIonsBCC[7] = scatterIonPos - lx + ly + lz;
neighborIonsBCC[8] = scatterIonPos - lx - ly + lz;
neighborIonsBCC[9] = scatterIonPos + lz * 2;
neighborIonsBCC[10] = scatterIonPos - lz * 2;
neighborIonsBCC[11] = scatterIonPos + ly * 2;
neighborIonsBCC[12] = scatterIonPos - ly * 2;
neighborIonsBCC[13] = scatterIonPos - lx * 2;
}
//set DiPrev to Di
DiPrev = Di;
//update current lambda to lambdaPrime
lambda = lambdaPrime;
//now the while condition of the mother do loop checks if the particle has lesser
energy than our lowest energy limit, ef.
}
while(e > ef);
//since we are out of the mother do loop now, the particle must have come to a
stop. So, increase the final particle distributions if the particle has not been
transmitted or backscattered.
if( ((transmitted == 0)) && ((backscattered == 0)) && ((insideChannel == 1)) )
{
ip = (int)(pl/cw + 1.0);
if(ip > 100) ip = 100;
//ipl[ip] = ipl[ip] + 1;
xsum = xsum + Di.x;
//my own bin function
selectedXBin = whichBin(Di.x, xx[Layer], numXBin);
//write the selected bin to the output file
//outStream << selectedXBin << endl;
//cout << x << endl << xx[Layer] << endl << numXBin << endl << selectedXBin;
xBin[selectedXBin] = xBin[selectedXBin] + 1;
//print final x value for plotting histogram
//cout << “ion “ << ih << “ final x: “ << Di.x << endl;
infoStream << “ion “ << ih << “ final x: “ << Di.x << endl;
//cout << Di.x << “,”;
rangeStream << Di.x << endl;
plsum = plsum + pl;
icsum = icsum + ic;
//ipl is the ion path length - the total avg. distance the ion travels
regardless of direction before it comes to stop
}
//that brings us to the end of one ion’s journey, now go to next ion by going back
to the for loop’s beginning..
}
//and this ends the monte carlo loop function. Take care of necessary structures and
variables that need to be cleared/deleted
outStream.close();
scatterStream.close();
infoStream << “Number of Backscattered Ions: “ << ib << endl;
infoStream.close();
rangeStream.close();
}
int whichNonUniformBin(double e, double arr[], int numBins)
{
double low = 0, high = arr[0];
if((e>=low) && (e<high))
return 0;
else
{
for(int i = 0; i < numBins; i++)
{
low += arr[i];
high += arr[i+1];
//cout << “\tlow: “ << low << “, high:” << high << endl;
if((e>=low) && (e<high))
return i;
}
}
}
144
//============================================================================
// Name : monte.cpp
// Author : Nazmus Saquib
// Version :
// Copyright :
// Description : BCA code in C++
//============================================================================
#include “Globals.h”
#include “scoef.h”
#include “rstop.h”
#include “muscle_bca.h”
#include “vectorGeometry.h”
const int numXBin = 100;
const int numIons = 1;
int xBin[numXBin+1] = {0};
int selectedXBin = 0;
double rho[4]={0.0};
int n[]={0,0,0,0};
double e0kev, m1, cw, ed, latticeConst;
int z1, hn, iy, nowout;
double dx[3] = {0.0};
int zt[3][7] = {0};
double mt[3][7] = {0.};
double t[3][7] = {0.};
int Layer; //use this for number of layers rather than the L in the program;
//remember this cannot be set to 0. Other loops/arrays may start from
//0, but keep this >= 1;
//the arrays..
double my[3][7]= {0},
ai[3][7]= {0},
fi[3][7]= {0},
ec[3][7]= {0},
io[3][7]= {0},
k[3]= {0},
kl[3][7]= {0};
double vf[3][7]= {0},
mu[3]= {0},
ioniz[3]= {0},
h[3]= {0},
xx[3]= {0},
m2[3]= {0.0},
z2[3]= {0},
c[3]= {0},
epsbk[3]= {0},
arho[3]= {0};
double a[3]= {0},
f[3]= {0},
lm[3]= {0},
pmax[3]= {0},
fd[3]= {0},
kd[3]= {0},
sbk[3]= {0},
lf[3]= {0},
yy[8]= {0};
double se[3][1000]= {0.0},
seo[1000]= {0.0},
epsdg[3]= {0.0};
double ls = 0., lo = 0., maximum = 0.;
double xsum = 0, x2sum = 0, x3sum = 0, x4sum = 0, plsum = 0, pl2sum = 0;
double avex = 0, vari = 0, sigma = 0, v = 0, v2 = 0, Gamma = 0, beta = 0, y = 0, avepl
= 0, sigpl = 0, avecol = 0;
int i = 0, j = 0;
int ib = 0, it = 0;
double eb = 0.0, et = 0.0;
int icsum = 0;
double y2sum = 0, xy2sum = 0, x2y2su = 0, y4sum = 0;
double tau = 0;
int iii = -1;
//my dummy vars
int w; double q;
//my customized data structures or vars
scoefData scoefz1;
rstopData rstp;
//these vars (continuing from this line) are added later as needed, vars that were not
declared in the initialization of trim85 but showed up in the middle.
double e0, ef;
int iz;
double alfa, alpha;
double tmin, da;
double L0;
int iz1;
double ee;
int izt;
double nh;
double epso;
int ih;
double e;
//boolean for keeping track of a particle being transmitted or backscattered
int transmitted = 0;
int backscattered = 0;
//boolean for keeping track of channeling
int insideChannel = 1;
//boolean for determining whether to scatter from neighbor atoms
int neighborFlag = 0;
//main function
int main()
{
cout << “Initializing” << endl;
Initialize(“IronInput.dat”);
calculateAvgMassOfLayer();
getStoppingForTarget();
setInitialConditions();
MonteCarlo();
/* *********************** Testing Ground for arrays and variables
******************** */
for (w = 1; w <= 8; w++) cout << “\t “ << yy[w];
for (w = 1; w <= 3; w++) cout << “\n\t “ << xx[w];
cout << “CW or L0: “ << L0;
//(trouble! The values of n[] elements are changing like crazy)
cout << endl << n[0] << “\t” << n[1] << “\t” << n[2] << “\t” << n[3] << endl;
cout << endl << rho[0] << “\t” << rho[1] << “\t” << rho[2] << “\t” << rho[3] <<
“\t” << rho[4] << endl;
//test z2[], m2[] arrays
for (w = 1; w <= Layer; w++) cout << “\t “ << z2[w];
for (w = 1; w <= Layer; w++) cout << “\n\t “ << m2[w];
//test the se values
cout << endl << se[1][1000] << “ “ << se[2][1000] << “ “ << se[3][1000] << endl;
//test the se[] values by printing 10th element from the array (to be implemented)
//for (w = 1; w <= 100; w++)
//{
//for (int sss = 1; sss <= 50; sss++)
//{
//cout << “\t” << mpart[w][sss];
//}
//}
/* *********************** End of Testing Ground ************************** */
cout << endl;
//Now print values of each bin in xBin
//for (w = 1; w <= numXBin; w++) cout << xBin[w] << “,”;
//print final x values
cout << endl;
cout << “Number of Backscattered Ions: “ << ib << endl;
cout << “Number of Transmitted Ions: “ << it << endl;
return 0;
}
//end of main
//Helper functions follow from here
//initialize variables and setup each layer over here
void Initialize(char* filename)
{
//Read command file
ifstream instream;
instream.open(filename,ios::in);
cout << filename;
if (!instream)
{
exitOnError(filename);
}
instream >> e0kev >> z1 >> m1 >> latticeConst >> hn >> cw >> ed >> iy >> nowout;
instream >> dx[1] >> rho[1];
instream >> zt[1][1] >> mt[1][1] >> t[1][1];
instream >> n[1];
instream >> dx[2] >> rho[2];
instream >> zt[2][1] >> mt[2][1] >> t[2][1];
instream >> n[2];
instream >> dx[3] >> rho[3];
instream >> zt[3][1] >> mt[3][1] >> t[3][1];
instream >> n[3];
for (w = 0; w <= 3; w++)
{ if (n[w] != 1) n[w] = 1; }
instream.close();
Layer = 3;
//done with primary (crude) setup, off to reading scoef.dat file
iz = z1;
getstructScoef(iz, scoefz1, “scoef1.dat”); //used to get pcoef data yy in trim85
//so we put the values in yy here immediately
for (w = 1; w <= 8; w++)
{ yy[w] = scoefz1.pcoef[w]; }
//note: although yy turns out to be just a dummy array
e0 = e0kev*1000; //convert to ev.
if (ed == 0.) ed = 25.0;
ef = Max(5.0, e0kev*0.1);
//alfa = angle of incidence, alpha = radian of alfa
alfa = 0.;
alpha = alfa*Pi/180;
tmin = 5.0;
tau = 0.0;
da = 3.0;
if (iy == 0) iy = 16381;
//now calculate the total depth of each layer = xx(l), and grid spacing cw
xx[1] = dx[1];
for (w = 2; w <= 3; w++) { xx[w] = dx[w] + xx[w-1]; }
if (cw == 0) cw = 0.01*xx[3];
L0 = cw;
//take care of any custom variable or struct I made
rstp.vfermi = 0.0; //set this to 0. for the time being (see log for explanation)
//now, off to avg mass of layer in the next void function
}
//avg mass and atomic number of each layer
void calculateAvgMassOfLayer()
{
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
h[LL] = h[LL] + t[LL][w];
//cout << “testing here..” << rstp.vfermi << endl;
}
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
t[LL][w] = t[LL][w]/h[LL];
m2[LL] = m2[LL] + t[LL][w] * mt[LL][w];
z2[LL] = z2[LL] + t[LL][w] * zt[LL][w];
//note: z2 wont be an integer once t has a value other than 1.0??
//so are we calculating average atomic number here? why?
}
}
//done with this, off to finding electronic stopping powers in the next function
}
void getStoppingForTarget()
{
iz1 = z1; ee = 0;
for (int LL = 1; LL <= Layer; LL++)
{
arho[LL] = rho[LL] * 0.6022/(m2[LL]);
mu[LL] = m1/(m2[LL]);
int ii = n[LL];
for (int nn = 1; nn <= ii; nn++)
{
//set rstp.se[1..1000] = 0. Clear it for the next loop
for (w = 1; w <= 1000; w++)
{ rstp.se[w] = 0.; }
izt = zt[LL][nn];
//calling getrstop now. units, lfctr, vfermi = 1 (doesnt matter)
getrStop(iz1, izt, e0kev, 1, 1., 1., rstp); //rstp defined in header
//set this anyway, though I dont calculate this in RSTOP
vf[LL][nn] = rstp.vfermi; //which is just set 0 in the struct def.
for (w = 1; w <= 1000; w++)
{
se[LL][w] = se[LL][w] + rstp.se[w] * t[LL][nn] * arho[LL];
}
}
}
//now, off to setting up initial conditions next function
}
void setInitialConditions()
{
nh = hn; //number of histories
for (int LL = 1; LL <= Layer; LL++)
{
a[LL] = 0.5292 * 0.8853 / ( pow(z1, 0.23) + pow(z2[LL], 0.23) );
//now calculate the mean flight path with the conditions given in trim85
f[LL] = a[LL] * m2[LL] / ( z1 * z2[LL] * 14.4 * (m1 + m2[LL] ) );
epso = e0 * f[LL];
epsdg[LL] = tmin * f[LL] * pow( (1.0 + mu[LL]) , 2) / (4.0 * mu[LL]);
fd[LL] = 0.01 * pow( z2[LL], (-7.0/3.0) );
kd[LL] = 0.1334 * pow ( z2[LL], (2.0/3.0) ) / sqrt( m2[LL] );
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
my[LL][w] = m1/mt[LL][w];
ec[LL][w] = 4.0 * my[LL][w] / pow( ( 1.0 + my[LL][w] ), 2);
ai[LL][w] = 0.5292 * 0.8853 / ( pow(z1,0.23) + pow(zt[LL][w],0.23) );
fi[LL][w] = ai[LL][w] * mt[LL][w] / ( z1 * zt[LL][w] * 14.4 * ( m1 + mt[LL][w] ) );
}
}
cout << “Setup finished. Starting Monte Carlo Loops..”;
//off to monte carlo loop in next routine
}
void MonteCarlo()
{
//custom variables and arrays for this section
double e;
double cosin = 0.0, siny = 0.0, sine = 0.0, cosy = 0.0;
double pl = 0.0;
int ic;
int LL = 1;
double eps;
double eeg;
double p;
double b;
int ie, ia; //not sure if ie or ia should be double. They are used to access elements
of the m[][] array at some point
double see;
double dee;
double s2, c2, ct, st;
double r, rr;
double ex1, ex2, ex3, ex4;
double v, v1;
double fr, fr1;
double q;
double roc, sqe;
double cc, aa, ff;
double delta, co;
double den;
double phi, psi;
double x1;
int ip;
//variables for crystal calculations
double sep = 0.0;
int ionCounter = 0;
double p1, p2;
double Theta = 0.0;
double rTheta = 0.0, rPhi = 0.0;
double thetaThreshold = 0.5;
double crystalMuonY = 0.0, crystalMuonZ = 0.0;
//amount of translations in y and z axes
double translationY = 0.0, translationZ = 0.0;
//Scatter Plot variables
const int numScatterPlotBins = 5;
double scatterPlot[numScatterPlotBins + 1] = {0.0};
//Vector declarations
//lattice constant of Target (input from file)
double latticeConstant = latticeConst;
Vector3 ions[4];
Vector3 ionsOrdered[4];
Vector3 neighborIonsBCC[14];
Vector3 neighborIonsFCC[14];
Vector3 ionTranslationY(0,translationY,0);
Vector3 ionTranslationZ(0,0,translationZ);
Vector3 unitzplus, unitzminus, unityplus, unityminus, unitxplus, unitxminus;
unitzplus.z = 1;
unitzminus.z = -1;
unityplus.y = 1;
unityminus.y = -1;
unitxplus.x = 1;
unitxminus.x = -1;
Vector3 initialDirection(1,0,0);
Vector3 d;
d.x = 1;
d *= latticeConstant/2;
Vector3 lx(latticeConstant/2, 0, 0);
Vector3 ly(0, latticeConstant/2, 0);
Vector3 lz(0, 0, latticeConstant/2);
Vector3 lambda;
Vector3 lambdaPrime;
Vector3 pVector;
Vector3 pUnitVector;
Vector3 sepVector;
Vector3 Di;
Vector3 DiPrev;
//Vector3 DiPrevToDi;
Vector3 delX;
Vector3 delX1, delX2;
Vector3 dummy1, dummy2, temp;
Vector3 scatterIonPos;
//initialize the random number generator
srand(time(NULL));
//open file to write output
ofstream outStream;
outStream.open(“coords0.txt”);
if(outStream.fail())
{
exitOnError(“Could not open Output file”);
}
//write basic information in the output file
//number of ions, ion energy, total depth, depth of each layer
outStream << nh << “\t” << e0kev << “\t” << xx[Layer] << “\t” << dx[1] << “\t”
<< dx[2] << “\t” << dx[3] << endl;
//open scatter plot file to write current Y and Z coordinates of muons at designated
intervals
ofstream scatterStream;
scatterStream.open(“scatterOut1.txt”);
if(scatterStream.fail())
{
exitOnError(“Could not open Scatter Plot Output file”);
}
//open range distribution file to write final X coordinates of muons
ofstream rangeStream;
rangeStream.open(“rangeOut1.txt”);
if(rangeStream.fail())
{
exitOnError(“Could not open Range Distribution Output file”);
}
//Open general information dump file
ofstream infoStream;
infoStream.open(“info1.txt”);
if(infoStream.fail())
{
exitOnError(“Could not open general information Output file”);
}
//Entering the target
//First set up for the top layer
for (ih = 1; ih <= nh; ih++)
{
avex = xsum / Max(1.0, (float)(ih - ib - it - 1));
if (talk == 2) cout << “Average ion range so far: “ << avex << “ angstroms.”
<<endl;
if (talk > 2) cout << “Now starting ion number “ << ih << endl;
e = e0;
//set scatterPlot array (the intervals)
scatterPlot[0] = 10;
scatterPlot[1] = 30;
scatterPlot[2] = 50;
scatterPlot[3] = 100;
scatterPlot[4] = 150;
scatterPlot[5] = 200;
/*
for(int ccc = 0; ccc <= numScatterPlotBins; ccc++)
{
cout << “scatter plot “ << ccc << “: “ << scatterPlot[ccc] << endl;
}
*/
//Initial Ion Positions
ions[0] = d + ionTranslationZ + unitzminus * (latticeConstant/2);
ions[1] = d + ionTranslationZ + unitzplus * (latticeConstant/2);
ions[2] = d * 2 + ionTranslationY + unityminus * (latticeConstant/2);
ions[3] = d * 2 + ionTranslationY + unityplus * (latticeConstant/2);
//Create a polygon that resides on the lateral axes.
//The points are put on anticlockwise order, which is important for
//testing whether the test point lies on this polygon
ionsOrdered[0] = ions[0];
ionsOrdered[1] = ions[2];
ionsOrdered[2] = ions[1];
ionsOrdered[3] = ions[3];
//generate random theta and phi angles.
rTheta = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * thetaThreshold;
rPhi = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * 2 * Pi;
//find corresponding x, y and z components of the direction vector.
//radius of the direction vector is 1
initialDirection.x = cos(rTheta);
initialDirection.z = sin(rTheta) * cos(rPhi);
initialDirection.y = sin(rTheta) * sin(rPhi);
//set the counter to 0 for a new ion
ionCounter = 0;
pl = 0.0;
ic = 0;
//set initial DiPrev - the origin
DiPrev.x = 0.0; DiPrev.y = 0.0; DiPrev.z = 0.0;
//set initial lambda, the direction of motion. Normalize it.
lambda.clear();
lambda = initialDirection;
lambda.normalize();
//set initial delX to origin
delX.clear();
//clear the dummy delX vectors, set them to origin
delX1.clear();
delX2.clear();
dummy1.clear();
dummy2.clear();
temp.clear();
LL = 1;
//set transmitted and backscattered to false
transmitted = 0;
backscattered = 0;
//set channeling to true
insideChannel = 1;
neighborFlag = 0;
//write the initial coordinates to the output file
outStream << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << endl << “Initial: “;
//cout << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << “r1 = “ << r1 << endl;
//cycle for each collision until the energy of the particle becomes too low, or
the particle backscatters, or it goes out of the last layer (transmission)
//needs a do while loop here,
//which I will mention as the ‘mother loop’ from now.
do
{
ic = ic + 1;
eps = e * f[LL];
eeg = sqrt(eps*epsdg[LL]);
//pmax[LL] = a[LL] / (eeg + sqrt(eeg) + 0.125 * pow( eeg, 0.1) );
pmax[LL] = sqrt(3) * (latticeConstant / 2) * 0.7;
//Calculate impact parameter and choose the atom to scatter from.
//Do this for ion pairs 0,1 and 2,3.
if (ionCounter == 0)
{
delX1 = ions[0] - DiPrev;
delX2 = ions[1] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[0];
ions[0] = ions[1];
ions[1] = temp;
//cout << “Vertical Ions swapped” << endl;
}
}
if (ionCounter == 2)
{
delX1 = ions[2] - DiPrev;
delX2 = ions[3] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[2];
ions[2] = ions[3];
ions[3] = temp;
//cout << “Horizontal Ions swapped” << endl;
}
}
//now calculate impact parameter
if(neighborFlag == 0)
{
delX = ions[ionCounter] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
else if(neighborFlag == 1)
{
double impact[13] = {0.0};
double radial[13] = {0.0};
double S[13] = {0.0};
double sumS = 0.0;
double Probability[13] = {0.0};
double rnd_candidate = 0.0;
int selected_candidate = -1;
for(int ncount = 0; ncount <= 13; ncount++)
{
delX = neighborIonsBCC[ncount] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
//scatterIonPos = neighborIonsBCC[ncount];
impact[ncount] = p;
radial[ncount] = delX.magnitude();
S[ncount] = 1 / ( pow(impact[ncount],2) * radial[ncount] );
sumS += S[ncount];
//general scheme of selecting the neighbor ion
// if(p < pmax[LL])
// {
// scatterIonPos = neighborIonsBCC[ncount];
// //cout << “Neighbor “ << ncount << “ is selected” << endl;
// break;
// }
}
for(int ncount = 0; ncount <= 13; ncount++)
{
Probability[ncount] = S[ncount] / sumS;
}
//print out the probability array
cout << endl;
for(int ncount = 0; ncount <= 13; ncount++)
{
//cout << Probability[ncount] << “ “;
infoStream << Probability[ncount] << “ “;
}
infoStream << endl;
//cout << endl;
//random number between 0 and 1
rnd_candidate = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) );
//cout << “rand_candidate: “ << rnd_candidate << endl;
//choose the candidate for scattering
selected_candidate = whichNonUniformBin(rnd_candidate, Probability, 13);
//cout << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate <<
endl;
infoStream << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate
<< endl;
//assign the scatterIonPos variable to the selected neighbor
scatterIonPos = neighborIonsBCC[selected_candidate];
//cout << “Scattering Ion Position: “; scatterIonPos.printVector();
//find the essential quantities for the selected neighbor
delX = neighborIonsBCC[selected_candidate] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
//find eps and b using fi[LL][nn], using nn that I was supposed to find from above
//here im deliberately using nn = 1
eps = fi[LL][1] * e;
b = p / ai[LL][1];
if (eps > 10) //rutherford scattering
{
s2 = 1.0 / (1.0 + (1.0 + b * (1.0 + b)) * pow((2.0 * eps * b), 2) );
c2 = 1.0 - s2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
else //magic formula
{
r = b;
rr = -2.7 * log(eps * b);
if (rr >= b)//note >= sign instead < in trim85
{
rr = -2.7 * log(eps * rr);
if (rr >= b)//note >= sign instead < in trim85
{
r = rr;
}
}
//do while loop that replaces line 330 loop
do
{
ex1 = 0.18175 * exp(-3.1998 * r);
ex2 = 0.50986 * exp(-0.94229 * r);
ex3 = 0.28022 * exp(-0.4029 * r);
ex4 = 0.028171 * exp(-0.20162 * r);
v = (ex1 + ex2 + ex3 + ex4) / r;
v1 = -(v + 3.1998 * ex1 + 0.94229 * ex2 + 0.4029 * ex3 + 0.20162 * ex4) / r;
fr = b * b / r + v * r / eps - r;
fr1 = -b * b / (r * r) + (v + v1 * r) / eps - 1.0;
q = fr / fr1;
r = r - q;
}
while( (Abs(q / r)) > 0.001 );
roc = -2.0 * (eps - v) / v1;
sqe = sqrt(eps);
//5 parameter magic scattering calculation
//below is for universal potential
cc = (0.011615 + sqe) / (0.0071222 + sqe);
aa = 2.0 * eps * (1.0 + (0.99229 / sqe) ) * ( pow(b, cc) );
ff = ( sqrt(aa * aa + 1.0) - aa) * ( (9.3066 + eps) / (14.813 + eps) );
delta = (r - b) * aa * ff / (ff + 1.0);
co = (b + delta + roc) / (r + roc);
c2 = co * co;
s2 = 1.0 - c2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
Theta = acos(ct);
//we are done finding theta (in CM system). So calculate all other quantities.
//find separation and the separation vector.
phi = (Pi - Theta) / 2;
sep = p / tan(phi);
sepVector = lambda * sep;
//find theta in laboratory frame - psi
psi = atan(st / (ct + my[LL][1] ) );
//note: change my[LL][1] to my[LL][nn] when the above section is fixed.
if (psi < 0 ) psi = psi + Pi; //should I do this for crystals?
//find Di, the scattering point vector
Di = DiPrev + delX + pVector - sepVector;
//find new direction of motion
lambdaPrime = lambda * cos(psi) + pUnitVector * sin(psi);
lambdaPrime.normalize();
//find length of step, ls = distance of Di from DiPrev
ls = Di.getDistance(DiPrev);
//find energy lost due to electronic stopping, dee
ie = (int)(e/e0kev+0.5); //should it be 0.5? or less so that ie <=1000?
see = se[LL][ie];
if (e < e0kev) see = se[LL][1] * sqrt(e/e0kev);
dee = ls * see;
// den = energy transferred to recoil
den = ec[LL][1] * s2 * e; //note: I am using ec[LL][1] here instead of [LL][nn].
//cout << “den = “ << den << “, dee = “ << dee << endl;
infoStream << “den = “ << den << “, dee = “ << dee << endl;
e = e - den - dee;
//cout << endl<< “current ion energy: “ << e << endl;
if (dee > maximum) maximum = dee;
pl = pl + ls - tau;
//write the ion position to output file
outStream << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
if((ic%30)==0)
{
//cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
}
//determine which scatter plot Di’s x value belongs to.
//output the y and z coordinates to scatter plot file accordingly.
for(int cc = 0; cc <= numScatterPlotBins; cc++)
{
if( Di.x >= (scatterPlot[cc]) )
{
crystalMuonY = Di.y - translationY;
crystalMuonZ = Di.z - translationZ;
//cout << “scatter plot “ << ct << “: “ << scatterPlot[ct] << endl;
scatterStream << scatterPlot[cc] << “\t” << crystalMuonY << “\t” <<
crystalMuonZ << endl;
//set scatterPlot[ss] to a big number
scatterPlot[cc] = 10000;
//break out of this for loop
break;
}
}
//determine if Di is in the channeling region.
//insideChannel = Di.isInsidePolygon(ionsOrdered, 4);
//break out of parent loop if not inside the channel
if(insideChannel == 0)
{
cout << “Ion “ << ih << “ is out of Channel” << endl;
cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
break;
}
//determine which layer the next collision will be in
if (Di.x < 0.0) //particle is backscattered
{
backscattered = 1; //cout << “ion number “ << ih << “ backscattered.” << endl;
infoStream << “ion number “ << ih << “ backscattered.” << endl;
ib = ib + 1;
eb = eb + e;
break; //break out of ‘mother do loop’ and continue with the next session of
for loop.
}
//here we set the current or next layer the particle will be in
for (w = 1; w <= Layer; w++)
{
if ( (Di.x <= xx[w]) && (w == 1) )
{
LL = 1;
//cout << endl<<”ion is in layer “ << LL << endl;
break;
//break out of this For loop and go check if the particle is transmitted.
}
else if ( (Di.x <= xx[w]) && (Di.x > xx[w-1]) )
{
LL = w;
//cout << “ion is in layer “ << LL <<endl;
break; //break out of this For loop and go check if the particle is
transmitted.
}
}
//now, check for particle transmission, i.e. whether the particle went out of the
last layer.
if(Di.x >= xx[Layer])
{
//particle is transmitted, take care of appropriate variables and break
transmitted = 1;//cout << “ion number “ << ih << “ transmitted.” << endl;
it = it + 1;
et = et + e;
ia = 57.295779 * acos(cosin) / da + 1.0;
ie = 100 * e / e0 + 1.0;
//m[ie][ia] = m[ie][ia] + 1;//note: how is this possible? ie and ia should be
integers in order to access the elements of the array m[][]. But we calculate them as
doubles here!
break; //break out of the ‘mother’ do loop
}
//now take care of ionCounter and other variables for the next scattering
if(neighborFlag == 0)
{
if(ionCounter == 3)
{
//ionCounter = 0;
neighborFlag = 1;
scatterIonPos = ions[3];
//cout << endl << “got out of first two layers” << endl;
}
else
{
ionCounter++;
}
}
if(neighborFlag == 1)
{
//cout << “Updating Neighbor Ions” << endl;
neighborIonsBCC[0] = scatterIonPos + lx - ly + lz;
neighborIonsBCC[1] = scatterIonPos + lx + ly + lz;
neighborIonsBCC[2] = scatterIonPos + lx + ly - lz;
neighborIonsBCC[3] = scatterIonPos + lx - ly - lz;
neighborIonsBCC[4] = scatterIonPos + lx * 2;
neighborIonsBCC[5] = scatterIonPos - lx - ly - lz;
neighborIonsBCC[6] = scatterIonPos - lx + ly - lz;
neighborIonsBCC[7] = scatterIonPos - lx + ly + lz;
neighborIonsBCC[8] = scatterIonPos - lx - ly + lz;
neighborIonsBCC[9] = scatterIonPos + lz * 2;
neighborIonsBCC[10] = scatterIonPos - lz * 2;
neighborIonsBCC[11] = scatterIonPos + ly * 2;
neighborIonsBCC[12] = scatterIonPos - ly * 2;
neighborIonsBCC[13] = scatterIonPos - lx * 2;
}
//set DiPrev to Di
DiPrev = Di;
//update current lambda to lambdaPrime
lambda = lambdaPrime;
//now the while condition of the mother do loop checks if the particle has lesser
energy than our lowest energy limit, ef.
}
while(e > ef);
//since we are out of the mother do loop now, the particle must have come to a
stop. So, increase the final particle distributions if the particle has not been
transmitted or backscattered.
if( ((transmitted == 0)) && ((backscattered == 0)) && ((insideChannel == 1)) )
{
ip = (int)(pl/cw + 1.0);
if(ip > 100) ip = 100;
//ipl[ip] = ipl[ip] + 1;
xsum = xsum + Di.x;
//my own bin function
selectedXBin = whichBin(Di.x, xx[Layer], numXBin);
//write the selected bin to the output file
//outStream << selectedXBin << endl;
//cout << x << endl << xx[Layer] << endl << numXBin << endl << selectedXBin;
xBin[selectedXBin] = xBin[selectedXBin] + 1;
//print final x value for plotting histogram
//cout << “ion “ << ih << “ final x: “ << Di.x << endl;
infoStream << “ion “ << ih << “ final x: “ << Di.x << endl;
//cout << Di.x << “,”;
rangeStream << Di.x << endl;
plsum = plsum + pl;
icsum = icsum + ic;
//ipl is the ion path length - the total avg. distance the ion travels
regardless of direction before it comes to stop
}
//that brings us to the end of one ion’s journey, now go to next ion by going back
to the for loop’s beginning..
}
//and this ends the monte carlo loop function. Take care of necessary structures and
variables that need to be cleared/deleted
outStream.close();
scatterStream.close();
infoStream << “Number of Backscattered Ions: “ << ib << endl;
infoStream.close();
rangeStream.close();
}
int whichNonUniformBin(double e, double arr[], int numBins)
{
double low = 0, high = arr[0];
if((e>=low) && (e<high))
return 0;
else
{
for(int i = 0; i < numBins; i++)
{
low += arr[i];
high += arr[i+1];
//cout << “\tlow: “ << low << “, high:” << high << endl;
if((e>=low) && (e<high))
return i;
}
}
}
145
//============================================================================
// Name : monte.cpp
// Author : Nazmus Saquib
// Version :
// Copyright :
// Description : BCA code in C++
//============================================================================
#include “Globals.h”
#include “scoef.h”
#include “rstop.h”
#include “muscle_bca.h”
#include “vectorGeometry.h”
const int numXBin = 100;
const int numIons = 1;
int xBin[numXBin+1] = {0};
int selectedXBin = 0;
double rho[4]={0.0};
int n[]={0,0,0,0};
double e0kev, m1, cw, ed, latticeConst;
int z1, hn, iy, nowout;
double dx[3] = {0.0};
int zt[3][7] = {0};
double mt[3][7] = {0.};
double t[3][7] = {0.};
int Layer; //use this for number of layers rather than the L in the program;
//remember this cannot be set to 0. Other loops/arrays may start from
//0, but keep this >= 1;
//the arrays..
double my[3][7]= {0},
ai[3][7]= {0},
fi[3][7]= {0},
ec[3][7]= {0},
io[3][7]= {0},
k[3]= {0},
kl[3][7]= {0};
double vf[3][7]= {0},
mu[3]= {0},
ioniz[3]= {0},
h[3]= {0},
xx[3]= {0},
m2[3]= {0.0},
z2[3]= {0},
c[3]= {0},
epsbk[3]= {0},
arho[3]= {0};
double a[3]= {0},
f[3]= {0},
lm[3]= {0},
pmax[3]= {0},
fd[3]= {0},
kd[3]= {0},
sbk[3]= {0},
lf[3]= {0},
yy[8]= {0};
double se[3][1000]= {0.0},
seo[1000]= {0.0},
epsdg[3]= {0.0};
double ls = 0., lo = 0., maximum = 0.;
double xsum = 0, x2sum = 0, x3sum = 0, x4sum = 0, plsum = 0, pl2sum = 0;
double avex = 0, vari = 0, sigma = 0, v = 0, v2 = 0, Gamma = 0, beta = 0, y = 0, avepl
= 0, sigpl = 0, avecol = 0;
int i = 0, j = 0;
int ib = 0, it = 0;
double eb = 0.0, et = 0.0;
int icsum = 0;
double y2sum = 0, xy2sum = 0, x2y2su = 0, y4sum = 0;
double tau = 0;
int iii = -1;
//my dummy vars
int w; double q;
//my customized data structures or vars
scoefData scoefz1;
rstopData rstp;
//these vars (continuing from this line) are added later as needed, vars that were not
declared in the initialization of trim85 but showed up in the middle.
double e0, ef;
int iz;
double alfa, alpha;
double tmin, da;
double L0;
int iz1;
double ee;
int izt;
double nh;
double epso;
int ih;
double e;
//boolean for keeping track of a particle being transmitted or backscattered
int transmitted = 0;
int backscattered = 0;
//boolean for keeping track of channeling
int insideChannel = 1;
//boolean for determining whether to scatter from neighbor atoms
int neighborFlag = 0;
//main function
int main()
{
cout << “Initializing” << endl;
Initialize(“IronInput.dat”);
calculateAvgMassOfLayer();
getStoppingForTarget();
setInitialConditions();
MonteCarlo();
/* *********************** Testing Ground for arrays and variables
******************** */
for (w = 1; w <= 8; w++) cout << “\t “ << yy[w];
for (w = 1; w <= 3; w++) cout << “\n\t “ << xx[w];
cout << “CW or L0: “ << L0;
//(trouble! The values of n[] elements are changing like crazy)
cout << endl << n[0] << “\t” << n[1] << “\t” << n[2] << “\t” << n[3] << endl;
cout << endl << rho[0] << “\t” << rho[1] << “\t” << rho[2] << “\t” << rho[3] <<
“\t” << rho[4] << endl;
//test z2[], m2[] arrays
for (w = 1; w <= Layer; w++) cout << “\t “ << z2[w];
for (w = 1; w <= Layer; w++) cout << “\n\t “ << m2[w];
//test the se values
cout << endl << se[1][1000] << “ “ << se[2][1000] << “ “ << se[3][1000] << endl;
//test the se[] values by printing 10th element from the array (to be implemented)
//for (w = 1; w <= 100; w++)
//{
//for (int sss = 1; sss <= 50; sss++)
//{
//cout << “\t” << mpart[w][sss];
//}
//}
/* *********************** End of Testing Ground ************************** */
cout << endl;
//Now print values of each bin in xBin
//for (w = 1; w <= numXBin; w++) cout << xBin[w] << “,”;
//print final x values
cout << endl;
cout << “Number of Backscattered Ions: “ << ib << endl;
cout << “Number of Transmitted Ions: “ << it << endl;
return 0;
}
//end of main
//Helper functions follow from here
//initialize variables and setup each layer over here
void Initialize(char* filename)
{
//Read command file
ifstream instream;
instream.open(filename,ios::in);
cout << filename;
if (!instream)
{
exitOnError(filename);
}
instream >> e0kev >> z1 >> m1 >> latticeConst >> hn >> cw >> ed >> iy >> nowout;
instream >> dx[1] >> rho[1];
instream >> zt[1][1] >> mt[1][1] >> t[1][1];
instream >> n[1];
instream >> dx[2] >> rho[2];
instream >> zt[2][1] >> mt[2][1] >> t[2][1];
instream >> n[2];
instream >> dx[3] >> rho[3];
instream >> zt[3][1] >> mt[3][1] >> t[3][1];
instream >> n[3];
for (w = 0; w <= 3; w++)
{ if (n[w] != 1) n[w] = 1; }
instream.close();
Layer = 3;
//done with primary (crude) setup, off to reading scoef.dat file
iz = z1;
getstructScoef(iz, scoefz1, “scoef1.dat”); //used to get pcoef data yy in trim85
//so we put the values in yy here immediately
for (w = 1; w <= 8; w++)
{ yy[w] = scoefz1.pcoef[w]; }
//note: although yy turns out to be just a dummy array
e0 = e0kev*1000; //convert to ev.
if (ed == 0.) ed = 25.0;
ef = Max(5.0, e0kev*0.1);
//alfa = angle of incidence, alpha = radian of alfa
alfa = 0.;
alpha = alfa*Pi/180;
tmin = 5.0;
tau = 0.0;
da = 3.0;
if (iy == 0) iy = 16381;
//now calculate the total depth of each layer = xx(l), and grid spacing cw
xx[1] = dx[1];
for (w = 2; w <= 3; w++) { xx[w] = dx[w] + xx[w-1]; }
if (cw == 0) cw = 0.01*xx[3];
L0 = cw;
//take care of any custom variable or struct I made
rstp.vfermi = 0.0; //set this to 0. for the time being (see log for explanation)
//now, off to avg mass of layer in the next void function
}
//avg mass and atomic number of each layer
void calculateAvgMassOfLayer()
{
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
h[LL] = h[LL] + t[LL][w];
//cout << “testing here..” << rstp.vfermi << endl;
}
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
t[LL][w] = t[LL][w]/h[LL];
m2[LL] = m2[LL] + t[LL][w] * mt[LL][w];
z2[LL] = z2[LL] + t[LL][w] * zt[LL][w];
//note: z2 wont be an integer once t has a value other than 1.0??
//so are we calculating average atomic number here? why?
}
}
//done with this, off to finding electronic stopping powers in the next function
}
void getStoppingForTarget()
{
iz1 = z1; ee = 0;
for (int LL = 1; LL <= Layer; LL++)
{
arho[LL] = rho[LL] * 0.6022/(m2[LL]);
mu[LL] = m1/(m2[LL]);
int ii = n[LL];
for (int nn = 1; nn <= ii; nn++)
{
//set rstp.se[1..1000] = 0. Clear it for the next loop
for (w = 1; w <= 1000; w++)
{ rstp.se[w] = 0.; }
izt = zt[LL][nn];
//calling getrstop now. units, lfctr, vfermi = 1 (doesnt matter)
getrStop(iz1, izt, e0kev, 1, 1., 1., rstp); //rstp defined in header
//set this anyway, though I dont calculate this in RSTOP
vf[LL][nn] = rstp.vfermi; //which is just set 0 in the struct def.
for (w = 1; w <= 1000; w++)
{
se[LL][w] = se[LL][w] + rstp.se[w] * t[LL][nn] * arho[LL];
}
}
}
//now, off to setting up initial conditions next function
}
void setInitialConditions()
{
nh = hn; //number of histories
for (int LL = 1; LL <= Layer; LL++)
{
a[LL] = 0.5292 * 0.8853 / ( pow(z1, 0.23) + pow(z2[LL], 0.23) );
//now calculate the mean flight path with the conditions given in trim85
f[LL] = a[LL] * m2[LL] / ( z1 * z2[LL] * 14.4 * (m1 + m2[LL] ) );
epso = e0 * f[LL];
epsdg[LL] = tmin * f[LL] * pow( (1.0 + mu[LL]) , 2) / (4.0 * mu[LL]);
fd[LL] = 0.01 * pow( z2[LL], (-7.0/3.0) );
kd[LL] = 0.1334 * pow ( z2[LL], (2.0/3.0) ) / sqrt( m2[LL] );
}
for (int LL = 1; LL <= Layer; LL++)
{
int ii = n[LL];
for (w = 1; w <= ii; w++)
{
my[LL][w] = m1/mt[LL][w];
ec[LL][w] = 4.0 * my[LL][w] / pow( ( 1.0 + my[LL][w] ), 2);
ai[LL][w] = 0.5292 * 0.8853 / ( pow(z1,0.23) + pow(zt[LL][w],0.23) );
fi[LL][w] = ai[LL][w] * mt[LL][w] / ( z1 * zt[LL][w] * 14.4 * ( m1 + mt[LL][w] ) );
}
}
cout << “Setup finished. Starting Monte Carlo Loops..”;
//off to monte carlo loop in next routine
}
void MonteCarlo()
{
//custom variables and arrays for this section
double e;
double cosin = 0.0, siny = 0.0, sine = 0.0, cosy = 0.0;
double pl = 0.0;
int ic;
int LL = 1;
double eps;
double eeg;
double p;
double b;
int ie, ia; //not sure if ie or ia should be double. They are used to access elements
of the m[][] array at some point
double see;
double dee;
double s2, c2, ct, st;
double r, rr;
double ex1, ex2, ex3, ex4;
double v, v1;
double fr, fr1;
double q;
double roc, sqe;
double cc, aa, ff;
double delta, co;
double den;
double phi, psi;
double x1;
int ip;
//variables for crystal calculations
double sep = 0.0;
int ionCounter = 0;
double p1, p2;
double Theta = 0.0;
double rTheta = 0.0, rPhi = 0.0;
double thetaThreshold = 0.5;
double crystalMuonY = 0.0, crystalMuonZ = 0.0;
//amount of translations in y and z axes
double translationY = 0.0, translationZ = 0.0;
//Scatter Plot variables
const int numScatterPlotBins = 5;
double scatterPlot[numScatterPlotBins + 1] = {0.0};
//Vector declarations
//lattice constant of Target (input from file)
double latticeConstant = latticeConst;
Vector3 ions[4];
Vector3 ionsOrdered[4];
Vector3 neighborIonsBCC[14];
Vector3 neighborIonsFCC[14];
Vector3 ionTranslationY(0,translationY,0);
Vector3 ionTranslationZ(0,0,translationZ);
Vector3 unitzplus, unitzminus, unityplus, unityminus, unitxplus, unitxminus;
unitzplus.z = 1;
unitzminus.z = -1;
unityplus.y = 1;
unityminus.y = -1;
unitxplus.x = 1;
unitxminus.x = -1;
Vector3 initialDirection(1,0,0);
Vector3 d;
d.x = 1;
d *= latticeConstant/2;
Vector3 lx(latticeConstant/2, 0, 0);
Vector3 ly(0, latticeConstant/2, 0);
Vector3 lz(0, 0, latticeConstant/2);
Vector3 lambda;
Vector3 lambdaPrime;
Vector3 pVector;
Vector3 pUnitVector;
Vector3 sepVector;
Vector3 Di;
Vector3 DiPrev;
//Vector3 DiPrevToDi;
Vector3 delX;
Vector3 delX1, delX2;
Vector3 dummy1, dummy2, temp;
Vector3 scatterIonPos;
//initialize the random number generator
srand(time(NULL));
//open file to write output
ofstream outStream;
outStream.open(“coords0.txt”);
if(outStream.fail())
{
exitOnError(“Could not open Output file”);
}
//write basic information in the output file
//number of ions, ion energy, total depth, depth of each layer
outStream << nh << “\t” << e0kev << “\t” << xx[Layer] << “\t” << dx[1] << “\t”
<< dx[2] << “\t” << dx[3] << endl;
//open scatter plot file to write current Y and Z coordinates of muons at designated
intervals
ofstream scatterStream;
scatterStream.open(“scatterOut1.txt”);
if(scatterStream.fail())
{
exitOnError(“Could not open Scatter Plot Output file”);
}
//open range distribution file to write final X coordinates of muons
ofstream rangeStream;
rangeStream.open(“rangeOut1.txt”);
if(rangeStream.fail())
{
exitOnError(“Could not open Range Distribution Output file”);
}
//Open general information dump file
ofstream infoStream;
infoStream.open(“info1.txt”);
if(infoStream.fail())
{
exitOnError(“Could not open general information Output file”);
}
//Entering the target
//First set up for the top layer
for (ih = 1; ih <= nh; ih++)
{
avex = xsum / Max(1.0, (float)(ih - ib - it - 1));
if (talk == 2) cout << “Average ion range so far: “ << avex << “ angstroms.”
<<endl;
if (talk > 2) cout << “Now starting ion number “ << ih << endl;
e = e0;
//set scatterPlot array (the intervals)
scatterPlot[0] = 10;
scatterPlot[1] = 30;
scatterPlot[2] = 50;
scatterPlot[3] = 100;
scatterPlot[4] = 150;
scatterPlot[5] = 200;
/*
for(int ccc = 0; ccc <= numScatterPlotBins; ccc++)
{
cout << “scatter plot “ << ccc << “: “ << scatterPlot[ccc] << endl;
}
*/
//Initial Ion Positions
ions[0] = d + ionTranslationZ + unitzminus * (latticeConstant/2);
ions[1] = d + ionTranslationZ + unitzplus * (latticeConstant/2);
ions[2] = d * 2 + ionTranslationY + unityminus * (latticeConstant/2);
ions[3] = d * 2 + ionTranslationY + unityplus * (latticeConstant/2);
//Create a polygon that resides on the lateral axes.
//The points are put on anticlockwise order, which is important for
//testing whether the test point lies on this polygon
ionsOrdered[0] = ions[0];
ionsOrdered[1] = ions[2];
ionsOrdered[2] = ions[1];
ionsOrdered[3] = ions[3];
//generate random theta and phi angles.
rTheta = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * thetaThreshold;
rPhi = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) ) * 2 * Pi;
//find corresponding x, y and z components of the direction vector.
//radius of the direction vector is 1
initialDirection.x = cos(rTheta);
initialDirection.z = sin(rTheta) * cos(rPhi);
initialDirection.y = sin(rTheta) * sin(rPhi);
//set the counter to 0 for a new ion
ionCounter = 0;
pl = 0.0;
ic = 0;
//set initial DiPrev - the origin
DiPrev.x = 0.0; DiPrev.y = 0.0; DiPrev.z = 0.0;
//set initial lambda, the direction of motion. Normalize it.
lambda.clear();
lambda = initialDirection;
lambda.normalize();
//set initial delX to origin
delX.clear();
//clear the dummy delX vectors, set them to origin
delX1.clear();
delX2.clear();
dummy1.clear();
dummy2.clear();
temp.clear();
LL = 1;
//set transmitted and backscattered to false
transmitted = 0;
backscattered = 0;
//set channeling to true
insideChannel = 1;
neighborFlag = 0;
//write the initial coordinates to the output file
outStream << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << endl << “Initial: “;
//cout << DiPrev.x << “\t” << DiPrev.y << “\t” << DiPrev.z << endl;
//cout << “r1 = “ << r1 << endl;
//cycle for each collision until the energy of the particle becomes too low, or
the particle backscatters, or it goes out of the last layer (transmission)
//needs a do while loop here,
//which I will mention as the ‘mother loop’ from now.
do
{
ic = ic + 1;
eps = e * f[LL];
eeg = sqrt(eps*epsdg[LL]);
//pmax[LL] = a[LL] / (eeg + sqrt(eeg) + 0.125 * pow( eeg, 0.1) );
pmax[LL] = sqrt(3) * (latticeConstant / 2) * 0.7;
//Calculate impact parameter and choose the atom to scatter from.
//Do this for ion pairs 0,1 and 2,3.
if (ionCounter == 0)
{
delX1 = ions[0] - DiPrev;
delX2 = ions[1] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[0];
ions[0] = ions[1];
ions[1] = temp;
//cout << “Vertical Ions swapped” << endl;
}
}
if (ionCounter == 2)
{
delX1 = ions[2] - DiPrev;
delX2 = ions[3] - DiPrev;
dummy1 = delX1 % lambda;
dummy2 = delX2 % lambda;
p1 = sqrt( dummy1.scalarProduct( delX1 % lambda ) );
p2 = sqrt( dummy2.scalarProduct( delX2 % lambda ) );
if(p2 > p1)
{ //swap ion ordering
temp = ions[2];
ions[2] = ions[3];
ions[3] = temp;
//cout << “Horizontal Ions swapped” << endl;
}
}
//now calculate impact parameter
if(neighborFlag == 0)
{
delX = ions[ionCounter] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
else if(neighborFlag == 1)
{
double impact[13] = {0.0};
double radial[13] = {0.0};
double S[13] = {0.0};
double sumS = 0.0;
double Probability[13] = {0.0};
double rnd_candidate = 0.0;
int selected_candidate = -1;
for(int ncount = 0; ncount <= 13; ncount++)
{
delX = neighborIonsBCC[ncount] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
//scatterIonPos = neighborIonsBCC[ncount];
impact[ncount] = p;
radial[ncount] = delX.magnitude();
S[ncount] = 1 / ( pow(impact[ncount],2) * radial[ncount] );
sumS += S[ncount];
//general scheme of selecting the neighbor ion
// if(p < pmax[LL])
// {
// scatterIonPos = neighborIonsBCC[ncount];
// //cout << “Neighbor “ << ncount << “ is selected” << endl;
// break;
// }
}
for(int ncount = 0; ncount <= 13; ncount++)
{
Probability[ncount] = S[ncount] / sumS;
}
//print out the probability array
cout << endl;
for(int ncount = 0; ncount <= 13; ncount++)
{
//cout << Probability[ncount] << “ “;
infoStream << Probability[ncount] << “ “;
}
infoStream << endl;
//cout << endl;
//random number between 0 and 1
rnd_candidate = ( (double)rand()/((double)(RAND_MAX)+(double)(1)) );
//cout << “rand_candidate: “ << rnd_candidate << endl;
//choose the candidate for scattering
selected_candidate = whichNonUniformBin(rnd_candidate, Probability, 13);
//cout << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate <<
endl;
infoStream << “Ion: “ << ih << “\tSelected Candidate: “ << selected_candidate
<< endl;
//assign the scatterIonPos variable to the selected neighbor
scatterIonPos = neighborIonsBCC[selected_candidate];
//cout << “Scattering Ion Position: “; scatterIonPos.printVector();
//find the essential quantities for the selected neighbor
delX = neighborIonsBCC[selected_candidate] - DiPrev;
dummy1 = delX % lambda;
p = sqrt( dummy1.scalarProduct( delX % lambda ) );
//find impact parameter vector and it’s unit vector
pVector = dummy1 % lambda;
pUnitVector = pVector.unit();
}
//find eps and b using fi[LL][nn], using nn that I was supposed to find from above
//here im deliberately using nn = 1
eps = fi[LL][1] * e;
b = p / ai[LL][1];
if (eps > 10) //rutherford scattering
{
s2 = 1.0 / (1.0 + (1.0 + b * (1.0 + b)) * pow((2.0 * eps * b), 2) );
c2 = 1.0 - s2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
else //magic formula
{
r = b;
rr = -2.7 * log(eps * b);
if (rr >= b)//note >= sign instead < in trim85
{
rr = -2.7 * log(eps * rr);
if (rr >= b)//note >= sign instead < in trim85
{
r = rr;
}
}
//do while loop that replaces line 330 loop
do
{
ex1 = 0.18175 * exp(-3.1998 * r);
ex2 = 0.50986 * exp(-0.94229 * r);
ex3 = 0.28022 * exp(-0.4029 * r);
ex4 = 0.028171 * exp(-0.20162 * r);
v = (ex1 + ex2 + ex3 + ex4) / r;
v1 = -(v + 3.1998 * ex1 + 0.94229 * ex2 + 0.4029 * ex3 + 0.20162 * ex4) / r;
fr = b * b / r + v * r / eps - r;
fr1 = -b * b / (r * r) + (v + v1 * r) / eps - 1.0;
q = fr / fr1;
r = r - q;
}
while( (Abs(q / r)) > 0.001 );
roc = -2.0 * (eps - v) / v1;
sqe = sqrt(eps);
//5 parameter magic scattering calculation
//below is for universal potential
cc = (0.011615 + sqe) / (0.0071222 + sqe);
aa = 2.0 * eps * (1.0 + (0.99229 / sqe) ) * ( pow(b, cc) );
ff = ( sqrt(aa * aa + 1.0) - aa) * ( (9.3066 + eps) / (14.813 + eps) );
delta = (r - b) * aa * ff / (ff + 1.0);
co = (b + delta + roc) / (r + roc);
c2 = co * co;
s2 = 1.0 - c2;
ct = 2.0 * c2 - 1.0;
st = sqrt(1.0 - ct * ct);
}
Theta = acos(ct);
//we are done finding theta (in CM system). So calculate all other quantities.
//find separation and the separation vector.
phi = (Pi - Theta) / 2;
sep = p / tan(phi);
sepVector = lambda * sep;
//find theta in laboratory frame - psi
psi = atan(st / (ct + my[LL][1] ) );
//note: change my[LL][1] to my[LL][nn] when the above section is fixed.
if (psi < 0 ) psi = psi + Pi; //should I do this for crystals?
//find Di, the scattering point vector
Di = DiPrev + delX + pVector - sepVector;
//find new direction of motion
lambdaPrime = lambda * cos(psi) + pUnitVector * sin(psi);
lambdaPrime.normalize();
//find length of step, ls = distance of Di from DiPrev
ls = Di.getDistance(DiPrev);
//find energy lost due to electronic stopping, dee
ie = (int)(e/e0kev+0.5); //should it be 0.5? or less so that ie <=1000?
see = se[LL][ie];
if (e < e0kev) see = se[LL][1] * sqrt(e/e0kev);
dee = ls * see;
// den = energy transferred to recoil
den = ec[LL][1] * s2 * e; //note: I am using ec[LL][1] here instead of [LL][nn].
//cout << “den = “ << den << “, dee = “ << dee << endl;
infoStream << “den = “ << den << “, dee = “ << dee << endl;
e = e - den - dee;
//cout << endl<< “current ion energy: “ << e << endl;
if (dee > maximum) maximum = dee;
pl = pl + ls - tau;
//write the ion position to output file
outStream << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
if((ic%30)==0)
{
//cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
}
//determine which scatter plot Di’s x value belongs to.
//output the y and z coordinates to scatter plot file accordingly.
for(int cc = 0; cc <= numScatterPlotBins; cc++)
{
if( Di.x >= (scatterPlot[cc]) )
{
crystalMuonY = Di.y - translationY;
crystalMuonZ = Di.z - translationZ;
//cout << “scatter plot “ << ct << “: “ << scatterPlot[ct] << endl;
scatterStream << scatterPlot[cc] << “\t” << crystalMuonY << “\t” <<
crystalMuonZ << endl;
//set scatterPlot[ss] to a big number
scatterPlot[cc] = 10000;
//break out of this for loop
break;
}
}
//determine if Di is in the channeling region.
//insideChannel = Di.isInsidePolygon(ionsOrdered, 4);
//break out of parent loop if not inside the channel
if(insideChannel == 0)
{
cout << “Ion “ << ih << “ is out of Channel” << endl;
cout << Di.x << “\t” << Di.y << “\t” << Di.z << endl;
break;
}
//determine which layer the next collision will be in
if (Di.x < 0.0) //particle is backscattered
{
backscattered = 1; //cout << “ion number “ << ih << “ backscattered.” << endl;
infoStream << “ion number “ << ih << “ backscattered.” << endl;
ib = ib + 1;
eb = eb + e;
break; //break out of ‘mother do loop’ and continue with the next session of
for loop.
}
//here we set the current or next layer the particle will be in
for (w = 1; w <= Layer; w++)
{
if ( (Di.x <= xx[w]) && (w == 1) )
{
LL = 1;
//cout << endl<<”ion is in layer “ << LL << endl;
break;
//break out of this For loop and go check if the particle is transmitted.
}
else if ( (Di.x <= xx[w]) && (Di.x > xx[w-1]) )
{
LL = w;
//cout << “ion is in layer “ << LL <<endl;
break; //break out of this For loop and go check if the particle is
transmitted.
}
}
//now, check for particle transmission, i.e. whether the particle went out of the
last layer.
if(Di.x >= xx[Layer])
{
//particle is transmitted, take care of appropriate variables and break
transmitted = 1;//cout << “ion number “ << ih << “ transmitted.” << endl;
it = it + 1;
et = et + e;
ia = 57.295779 * acos(cosin) / da + 1.0;
ie = 100 * e / e0 + 1.0;
//m[ie][ia] = m[ie][ia] + 1;//note: how is this possible? ie and ia should be
integers in order to access the elements of the array m[][]. But we calculate them as
doubles here!
break; //break out of the ‘mother’ do loop
}
//now take care of ionCounter and other variables for the next scattering
if(neighborFlag == 0)
{
if(ionCounter == 3)
{
//ionCounter = 0;
neighborFlag = 1;
scatterIonPos = ions[3];
//cout << endl << “got out of first two layers” << endl;
}
else
{
ionCounter++;
}
}
if(neighborFlag == 1)
{
//cout << “Updating Neighbor Ions” << endl;
neighborIonsBCC[0] = scatterIonPos + lx - ly + lz;
neighborIonsBCC[1] = scatterIonPos + lx + ly + lz;
neighborIonsBCC[2] = scatterIonPos + lx + ly - lz;
neighborIonsBCC[3] = scatterIonPos + lx - ly - lz;
neighborIonsBCC[4] = scatterIonPos + lx * 2;
neighborIonsBCC[5] = scatterIonPos - lx - ly - lz;
neighborIonsBCC[6] = scatterIonPos - lx + ly - lz;
neighborIonsBCC[7] = scatterIonPos - lx + ly + lz;
neighborIonsBCC[8] = scatterIonPos - lx - ly + lz;
neighborIonsBCC[9] = scatterIonPos + lz * 2;
neighborIonsBCC[10] = scatterIonPos - lz * 2;
neighborIonsBCC[11] = scatterIonPos + ly * 2;
neighborIonsBCC[12] = scatterIonPos - ly * 2;
neighborIonsBCC[13] = scatterIonPos - lx * 2;
}
//set DiPrev to Di
DiPrev = Di;
//update current lambda to lambdaPrime
lambda = lambdaPrime;
//now the while condition of the mother do loop checks if the particle has lesser
energy than our lowest energy limit, ef.
}
while(e > ef);
//since we are out of the mother do loop now, the particle must have come to a
stop. So, increase the final particle distributions if the particle has not been
transmitted or backscattered.
if( ((transmitted == 0)) && ((backscattered == 0)) && ((insideChannel == 1)) )
{
ip = (int)(pl/cw + 1.0);
if(ip > 100) ip = 100;
//ipl[ip] = ipl[ip] + 1;
xsum = xsum + Di.x;
//my own bin function
selectedXBin = whichBin(Di.x, xx[Layer], numXBin);
//write the selected bin to the output file
//outStream << selectedXBin << endl;
//cout << x << endl << xx[Layer] << endl << numXBin << endl << selectedXBin;
xBin[selectedXBin] = xBin[selectedXBin] + 1;
//print final x value for plotting histogram
//cout << “ion “ << ih << “ final x: “ << Di.x << endl;
infoStream << “ion “ << ih << “ final x: “ << Di.x << endl;
//cout << Di.x << “,”;
rangeStream << Di.x << endl;
plsum = plsum + pl;
icsum = icsum + ic;
//ipl is the ion path length - the total avg. distance the ion travels
regardless of direction before it comes to stop
}
//that brings us to the end of one ion’s journey, now go to next ion by going back
to the for loop’s beginning..
}
//and this ends the monte carlo loop function. Take care of necessary structures and
variables that need to be cleared/deleted
outStream.close();
scatterStream.close();
infoStream << “Number of Backscattered Ions: “ << ib << endl;
infoStream.close();
rangeStream.close();
}
int whichNonUniformBin(double e, double arr[], int numBins)
{
double low = 0, high = arr[0];
if((e>=low) && (e<high))
return 0;
else
{
for(int i = 0; i < numBins; i++)
{
low += arr[i];
high += arr[i+1];
//cout << “\tlow: “ << low << “, high:” << high << endl;
if((e>=low) && (e<high))
return i;
}
}
}
146